不少东西已经记不起来了,想到一点写一点,碰到一点写一点,慢慢累积。函数
关于#spa
#在宏定义中用于替换传入变量的字符,例如: #define whole_operation(n) do { printf(#n "=%d\n", (n));} while(0);接口
调用whole_operation(5*6), 输出:5*6=30, 有助于增长输出的可读性。io
关于##ast
##是c99中定义的用于粘连两个符号,标识符或参数。例如:#define name_index(index) name_##index变量
调用name_index(1),则生成name_1变量, 因此不少时候##用于动态的调用标识符具备必定规律的函数,宏或者变量。防火墙
举个列子,若是如今有add_arg_1(), add_arg_2()两个函数,只有在运行时才知道调用哪一个函数,那么可使用以下代码:gc
#define call_add_arg(argc) add_arg_##argc()程序
IPnet的log模块中,由于log级别不一样而log级别的前几个标识符都是IPCOM_LOG_,因此采用IPCOM_LOG_##x的方式在运行是判断须要输出什么级别的log。call
关于不定参数...
好久之前在防火墙上作log模块的时候,用到一个比较有意思的trick。由于log要接收不一样模块的不一样信息,可是每一个模块都含有本身独特的信息,为了保证全部信息都能被log接受,当时用了不定参的函数做为log的接口log(msgid, ...),经过va_list ap; va_start(ap, firstarg); va_arg(ap, type);va_end(ap);的方式来接受传入的各个参数。事实上,大多数prinf也是经过这个方式实现。 可是这种方式的函数调用容易出问题, 函数不知道何时参数结束,有可能致使程序崩溃。
C99定义了__VA_ARGS__ 用于接受不定参数的宏:#define LOG(msgid, ...) log(msgid, __VA_ARGS__, lastarg) 或者#define LOG(msgid, arg...) log(msgid, arg, lastarg) lastarg是预约义的用于标识结束的宏或变量, 若不用__VA_ARGS__,则需用arg...来替代。 这样,LOG函数就能够接受任意多1个以上参数而不须要关系何时结束。那么若是LOG调用时只有一个msgid参数,就会变成log(msgid,,lastarg),这时候就须要借助##的另外一个做用,若是##,后面没有参数,那么逗号就会被省略,因而LOG函数的最终定义变成: #define LOG(msgid, ...) log(msgid, ##__VA_ARGS__, lastarg)