#define swap(x,y) \ do { unsigned long _temp=x; x=y; y=_tmp} while (0) swap(1,2); 将被替换为: do { unsigned long _temp=1; 1=2; 2=_tmp} while (0); 在Linux内核源代码中对这种do-while(0)语句有这广泛的应用.
2, 有的函数宏是无法用do-while(0)来实现的, 所以在调用时不能带上";", 最好在调用后添加注释说明. eg_3.8: #define incr(v, low, high) \ for ((v) = (low),; (v) <= (high); (v)++) 只能以这样的形式被调用: incr(a, 1, 10) /* increase a form 1 to 10 */
(3) #define所定义的宏的作用域 宏在定义之后才生效, 若宏定义被#undef取消, 则#undef之后该宏无效. 并且字符串中的宏不会被识别 e.g. #define ONE 1 sum = ONE + TWO /* sum = 1 + TWO */ #define TWO 2 sum = ONE + TWO /* sum = 1 + 2 */ #undef ONE sum = ONE + TWO /* sum = ONE + 2 */
char c[] = "TWO" /* c[] = "TWO", NOT "2"! */
(4) 宏的替换可以是递归的, 所以可以嵌套定义宏. e.g. # define ONE NUMBER_1 # define NUMBER_1 1 int a = ONE /* a = 1 */
2, #undef #undef用来取消宏定义, 它与#define对立: #undef name 如够被取消的宏实际上没有被#define所定义, 针对它的#undef并不会产生错误. 当一个宏定义被取消后, 可以再度定义它.
(1) #pragma GCC dependency dependency测试当前文件(既该语句所在的程序代码)与指定文件(既#pragma语句最后列出的文件)的时间戳. 如果指定文件比当前文件新, 则给出警告信息. e.g. 在demo.c中给出这样一句: #pragma GCC dependency "temp-file" 然后在demo.c所在的目录新建一个更新的文件: $ touch temp-file, 编译: $ gcc demo.c 会给出这样的警告信息: warning: current file is older than temp-file 如果当前文件比指定的文件新, 则不给出任何警告信息.
还可以在在#pragma中给添加自定义的警告信息. e.g. #pragma GCC dependency "temp-file" "demo.c needs to be updated!" 1.c:27:38: warning: extra tokens at end of #pragma directive 1.c:27:38: warning: current file is older than temp-file 注意: 后面新增的警告信息要用""引用起来, 否则gcc将给出警告信息.
(2) #pragma GCC poison token(s) 若源代码中出现了#pragma中给出的token(s), 则编译时显示警告信息. 它一般用于在调用你不想使用的函数时候给出出错信息. e.g. #pragma GCC poison scanf scanf("%d", &a); warning: extra tokens at end of #pragma directive error: attempt to use poisoned "scanf" 注意, 如果调用了poison中给出的标记, 那么编译器会给出的是出错信息. 关于第一条警告, 我还不知道怎么避免, 用""将token(s)引用起来也不行.