当前位置: 首页 > 我的程序代码 > 正文

C宏的一个技巧:可变参数

版权声明:本文可以转载,不过转载时请务必以超链接形式标明文章原始出处和作者信息及本声明

文章出处:http://www.latelee.org/my-library/c-macro-tricks.html

作者:李迟<www.latelee.org>

前天晚上,和一个朋友天南地北地聊一些技术问题。无意中给我一个网址http://www.nongnu.org。无意中我发现了GNU Coding Standards(现在的我对一些专业名词非常敏感),于是不由自主地点击了进去。结果让我大开眼界增长了见识。这些单表一处:错误信息格式及一些宏技巧。

GNU Coding StandardsFormatting Error Messages提到了错误信息的格式,大约如下:

source-file-name:lineno: message

联想到我以前的出错信息都没有添加源代码文件名称以及行号,只是一个简单的宏定义,如下:

#define unix_error_exit(error)

do{

fprintf(stderr, “%s: %sn”,

error, strerror(errno));

exit(1);

while(0)

于是再次修改,添加了__FILE__和__LINE__的信息,如下:

#define unix_error_exit(error)

do{

fprintf(stderr, “%s: %d: %s: %sn”,

__FILE__, __LINE__, error, strerror(errno));

exit(1);

while(0)

这个宏的打印信息效果如下:

main.c: 31: Open file error: No such file or directory.

本来想将函数名称也添加上去,但似乎有点长了,就不添加了。

关于错误信息处理,我还有另外的真正的函数版本。这是从APUE最后附录的例子的基础上稍作修改而成的。

一个例子如下:

void unix_error_exit(const char *fmt, …);

前缀为unix,这是表示这个处理系统调用的出错信息处理(GNU Coding Standards也强调了系统调用出错信息处理的重要性)。同样,上面的函数是不能打印源文件名称和行号的,现在需要添加上去,变成这个样子:

void unix_error_exit(const char *file_name, int line, const char *fmt, …);

在代码中很方便将参数file_name和line传递到缓冲区中。但我们需要的__FILE__和__LINE__,如果直接放到这个函数中,将不能实现我们的目标——因为我们不是打印这个函数的文件名和行号。

因此,我们必须在真正的调用处才能使用这两个宏。于是,很自然想到了宏定义:

#define x__unix_error_exit(fmt) unix_error_exit(__FILE__, __LINE__, fmt)

但是,这个宏定义只能带一个参数,像printf函数那种格式就不成功。——当然,对于简单的提示信息,这已经足够了。可以这样使用:

x_unix_error_exit(“Open file error”);

但是,能不能将这个宏也做成像printf那样,自由地带参数呢?APUE上的例子本来就是可以带多个参数,即使这里用不着,但是以后可能会有用得到的场合呢?这个问题我想了好久,也没什么方法。

今天在讨论上乱看帖子,不小心看到了一篇关于C宏技巧的文章:http://www.javaeye.com/topic/814136。里面有一个宏定义:

#define gnu_eprintf(format, args…)       fprintf(stderr, format, ##args)

对我帮助非常大,原来是可以这样的!于是我马上将我的代码作了修改,如下:

#define x_unix_error_exit(fmt, args…) unix_error_exit(__FILE__, __LINE__, fmt, ##args)

当然,也可以修改成为C99风格的:

#define x_unix_error_exit(fmt, …) unix_error_exit(__FILE__, __LINE__, fmt, __VA_ARGS__)

测试例子:

x_unix_error_exit(“%d %s Open file error”, 88, “hello world”);

效果如下:

main.c: 31: 88 hello world Open file error: No such file or directory.

当然,这里仅是测试而已,不过已经达到我们的目的。而这技巧,对于以后的日志函数将大有作用。

前一天还在为某一问题而烦恼,但今天不小心就找到了解决之法,或者这是冥冥中自有天意吧。我始终坚信我一直以来学的东西都会派上用场的,它们也相互有联系(最鲜明的例子就是我不将C语言只看成一门语言,它跟很多学科都有联系)。生活中很多东西也有联系,从多个角度分析问题,有时会对社会看得更深入一些,心态看开了,生活也自然不会忧郁。当然,每个人对幸福的定义是不同的。

PS:

1、本文涉及代码依然还在修改当中,错误难免存在,就不便公开,如果实在需要,可在文后留言给我。

2、google得来的一篇文章:

C Macro Tips and Tricks:

http://www.mikeash.com/pyblog/friday-qa-2010-12-31-c-macro-tips-and-tricks.html

本文固定链接: http://www.latelee.org/my-library/c-macro-tricks.html

如无特别说明,迟思堂工作室文章均为原创,转载请注明: C宏的一个技巧:可变参数 | 迟思堂工作室

目前暂无评论

发表评论

*

快捷键:Ctrl+Enter