一、参考文章
1、宏的高级使用--##,__VA_ARGS__, __FILE__, __FUNCTION__等
二、知识点
1、#和##运算符
1.1 #用在预编译语句里面可以把预编译函数的变量直接格式成字符串;如:#define Func1(x) printf("the square of " #x " is %d. ",(x)*(x))
调用Func1(30);则输出:the square of 30 is 900.
注意,不能直接在其它非预编译函数直接使用#aa的形式,假如main函数里面出现printf("the square of " #x " is %d. ",(x)*(x))是不能通过编译的.
1.2 ##宏连接符
举个例子:宏定义为#define XNAME(n) x##n,代码为:XNAME(4),则在预编译时,宏发现XNAME(4)与XNAME(n)匹配,则令 n 为 4,然后将右边的n的内容也变为4,
然后将整个XNAME(4)替换为 x##n,亦即 x4,故 最终结果为 XNAME(4) 变为 x4.
1 #include <stdio.h> 2 #define XNAME(n) x ## n 3 #define PRINT_XN(n) printf("x" #n " = %d/n", x ## n); 4 int main(void) 5 { 6 int XNAME(1) = 14; // becomes int x1 = 14; 7 int XNAME(2) = 20; // becomes int x2 = 20; 8 PRINT_XN(1); // becomes printf("x""1"" = %d/n", x1);即 9 //printf("x1 = %d/n", x1) 10 PRINT_XN(2); // becomes printf("x""2"" = %d/n", x2);即 11 //printf("x2 = %d/n", x2) 12 return 0; 13 } 14
2、可变参数
1)参考文章:C 语言的奇技淫巧
在 GUNC 中的扩展,其形式如下。
#define log_debug(fmt, args...) do { printf("gnu debug: " fmt, ## args); putchar('
'); } while(0);
2)参考文章:Linux c编程一站式学习的第21章 预处理
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
是空参数时,##
运算符把它前面的,
号“吃”掉了。
3)调试常用格式
// 常用格式 #ifdef DEBUG #define debug(fmt, args...) printf("debug: " fmt " ", ##args) // OR #define debug(fmt, ...) printf("debug: " fmt " ", ## __VA_ARGS__); #else #define debug(fmt,args...) #endif // 输出文件名、函数名、行数 #ifdef DEBUG #define debug(fmt, args...) printf("%s, %s, %d: " fmt , __FILE__, __FUNCTION__, __LINE__, ##args) #else #define debug(fmt, args...) #endif // 输出信息含有彩色 #ifdef DEBUG #define debug(fmt,args...) do{ printf("