前天晚上,和一个朋友天南地北地聊一些技术问题。无意中给我一个网址http://www.nongnu.org。无意中我发现了GNU Coding Standards(现在的我对一些专业名词非常敏感),于是不由自主地点击了进去。结果让我大开眼界增长了见识。这些单表一处:错误信息格式及一些宏技巧。
GNU Coding Standards中Formatting Error Messages提到了错误信息的格式,大约如下:
1 | source-file-name:lineno: message |
联想到我以前的出错信息都没有添加源代码文件名称以及行号,只是一个简单的宏定义,如下:
1 | #define unix_error_exit(error) \ |
于是再次修改,添加了__FILE__和__LINE__的信息,如下:
1 | #define unix_error_exit(error) \ |
这个宏的打印信息效果如下:
1 | main.c: 31: Open file error: No such file or directory. |
本来想将函数名称也添加上去,但似乎有点长了,就不添加了。 关于错误信息处理,我还有另外的真正的函数版本。这是从APUE最后附录的例子的基础上稍作修改而成的。 一个例子如下:
1 | void unix_error_exit(const char *fmt, ...); |
前缀为unix,这是表示这个处理系统调用的出错信息处理(GNU Coding Standards也强调了系统调用出错信息处理的重要性)。同样,上面的函数是不能打印源文件名称和行号的,现在需要添加上去,变成这个样子:
1 | void unix_error_exit(const char *file_name, int line, const char *fmt, ...); |
在代码中很方便将参数file_name和line传递到缓冲区中。但我们需要的__FILE__和__LINE__,如果直接放到这个函数中,将不能实现我们的目标——因为我们不是打印这个函数的文件名和行号。 因此,我们必须在真正的调用处才能使用这两个宏。于是,很自然想到了宏定义:
1 | #define x__unix_error_exit(fmt) unix_error_exit(__FILE__, __LINE__, fmt) |
但是,这个宏定义只能带一个参数,像printf函数那种格式就不成功。——当然,对于简单的提示信息,这已经足够了。可以这样使用:
1 | x_unix_error_exit("Open file error"); |
但是,能不能将这个宏也做成像printf那样,自由地带参数呢?APUE上的例子本来就是可以带多个参数,即使这里用不着,但是以后可能会有用得到的场合呢?这个问题我想了好久,也没什么方法。
今天在讨论上乱看帖子,不小心看到了一篇关于C宏技巧的文章:http://www.javaeye.com/topic/814136。里面有一个宏定义:
1 | #define gnu_eprintf(format, args...) fprintf(stderr, format, ##args) |
对我帮助非常大,原来是可以这样的!于是我马上将我的代码作了修改,如下:
1 | #define x_unix_error_exit(fmt, args...) unix_error_exit(__FILE__, __LINE__, fmt, ##args) |
当然,也可以修改成为C99风格的:
1 | #define x_unix_error_exit(fmt, ...) unix_error_exit(__FILE__, __LINE__, fmt, __VA_ARGS__) |
测试例子:
1 | x_unix_error_exit("%d %s Open file error", 88, "hello world"); |
效果如下:
1 | main.c: 31: 88 hello world Open file error: No such file or directory. |
当然,这里仅是测试而已,不过已经达到我们的目的。而这技巧,对于以后的日志函数将大有作用。
前一天还在为某一问题而烦恼,但今天不小心就找到了解决之法,或者这是冥冥中自有天意吧。我始终坚信我一直以来学的东西都会派上用场的,它们也相互有联系(最鲜明的例子就是我不将C语言只看成一门语言,它跟很多学科都有联系)。生活中很多东西也有联系,从多个角度分析问题,有时会对社会看得更深入一些,心态看开了,生活也自然不会忧郁。当然,每个人对幸福的定义是不同的。
PS:
1、本文涉及代码依然还在修改当中,错误难免存在,就不便公开,如果实在需要,可在文后留言给我。
2、google得来的一篇文章:C Macro Tips and Tricks