一:可变参数使用:
printf(fmt, ...)
#define DPRINTF(fmt, args...) printf(fmt, ##args)
args...表示fmt之后的参数可以是零个或者多个。
二:#和##只能在宏定义中使用
#是把宏参数变为一个字符串,##是把两个宏参数连接在一起
1.
#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main()
{
printf("%s\n",h(f(1,2))); // 输出:12
printf("%s\n",g(f(1,2))); // 输出:f(1,2)
printf("%s\n",g(1)); // 输出:1
printf("%d\n", f(1,2)); // 输出:12(数值)
return 0;
}
分析:
第 9行:#1 将1转换为字符串输出
第10行:1##2 将1和2连接结果为12,12是数字,故输出时用%d。注意并没有将12转换为字符串,如果需要将12作为字符串输出,需要再次使用h(a)这个宏,即第7行。
第 7行:因为h(a)是普通的宏(即没有#和##的宏),所以h(f(1,2))即是h(12),然后调用g(12),结果是字符串12
第 8行:因为g(a)是直接将a转换为字符串,所以将f(1,2)转换为字符串
2.
#include <stdio.h>
#define f(a,b) a##b
#define h(a,b) f(a,b)
int main()
{
printf("%s\n", h("hello", "world"));
return 0;
}
编译时错误信息:
error: pasting ""hello"" and ""world"" does not give a valid preprocessing token
printf("%s\n", f("hello", "world"));
原因分析:
根据C标准,用##操作后的结果必须是一个已经预定义过的符号,否则就是未定义的。
预定义的符号:头文件名, 等式, 预处理数字, 字符常数, 字符串值, 标点符号, 单个非空字符
具体参考:https://www.cnblogs.com/wb-DarkHorse/p/3588787.html
3. 上面出错的场景是自己想象当参数是字符串时,宏函数调用结果是什么样,以下是可能的一种使用场景。
参考:http://gcc.gnu.org/onlinedocs/gcc-4.3.3/cpp/Concatenation.html#Concatenation
#include <stdio.h>
#define COMMAND(name) {#name, name##_command}
void quit_command(void) {
return;
}
void help_command(void) {
return;
}
struct command
{
char *name;
void (*function) (void);
};
int main()
{
struct command commands[] = {
COMMAND (quit),
COMMAND (help),
};
return 0;
}
程序正常运行。