可变参数宏

定义宏时可以让宏接收可变参数,对于可变参数的定义,标准 C 和 GNU C(GNU 对 C的扩展)是不一样的。

标准 C

标准 C 对于可变参数的定义如下,使用...:

#define eprintf(...) fprintf (stderr, __VA_ARGS__)

在宏定义中,__VA_ARGS__ 代表了所有的可变参数。比如像下面使用宏 eprintf:

eprintf ("%s:%d: ", input_file, lineno)

那么 __VA_ARGS__ 就是 "%s:%d: ", input_file, lineno。

GNU C

GNU C 除了支持标准 C的定义之外,还有自己的一套定义,同样是定义宏 eprintf,GNU C 中可以定义成:

#define eprintf(args...) fprintf (stderr, args)

和标准 C 不同之处在于可变参标志...前面有一个参数名 args,在宏定义里面也没有 __VA_ARGS__,而是直接使用的参数名 args,两者是等价的,但是如果使用 GNU C 的方式,在宏定义中就不可以使用 __VA_ARGS__。

可变参数为空

假如定义了如下宏(不管是使用标准 C 方式还是 GNU C方式都可以,这里使用标准 C 的方式):

#define eprintf(format, ...) fprintf (stderr, format, __VA_ARGS__)

在标准 C 的环境下进行如下调用,不传递可变参数:

eprintf("success!\n");

宏的扩展将会报错,因为扩展出来后的形式如下:

fprintf(stderr, "success!\n",);

fprintf 最后一个参数后面多了一个逗号,这样将报错。这种情况在标准 C 下无法解决,但是 GNU C可以解决。GNU C 赋予 "##" 另一种特殊意义(不是字符串连接的意义了),如果在可变参数前面加上"##",当可变参数为空时,前面的逗号会被删除:

#define eprintf(format, ...) fprintf (stderr, format, ##__VA_ARGS__)

// 或者
#define eprintf(format, args...) fprintf(stderr, format, ##args)

当可变参数为空时,宏都会扩展成:

fprintf(stderr, "success!\n");

可以看到最后一个参数后面的逗号被删除了。

Clang 默认使用 GNU11,因此也支持这个功能。

 

posted @ 2022-03-19 15:13  chaoguo1234  阅读(1187)  评论(0编辑  收藏  举报