在函数式宏定义中,#
运算符用于创建字符串,#
运算符后面应该跟一个形参(中间可以有空格或Tab),例如:
#define STR(s) # s STR(hello world)
用cpp
命令预处理之后是"hello␣world"
,自动用"
号把实参括起来成为一个字符串,并且实参中的连续多个空白字符被替换成一个空格。
gcc
有一种扩展语法,如果##
运算符用在__VA_ARGS__
前面,除了起连接作用之外还有特殊的含义,例如内核代码net/netfilter/nf_conntrack_proto_sctp.c
中的:
#define DEBUGP(format, ...) printk(format, ## __VA_ARGS__)
printk
这个内核函数相当于printf
,也带有格式化字符串和可变参数,由于内核不能调用libc
的函数,所以另外实现了一个打印函数。这个函数式宏定义可以这样调用:DEBUGP("info no. %d", 1)
。也可以这样调用:DEBUGP("info")
。后者相当于可变参数部分传了一个空参数,但展开后并不是printk("info",)
,而是printk("info")
,当__VA_ARGS__
是空参数时,##
运算符把它前面的,
号“吃”掉了。