宏在 C 代码中十分普遍,最常见的用法莫过于定义一些有特殊含义的常量,或者控制编译过程。在最近阅读代码的过程中,有幸见识了几种不太常见的宏定义的用法,特总结一文。
这是很好理解的一种用法,目的其实就是用来注释代码,被”#if 0″和”#endif”包裹起来的代码是不会被编译的,而用通常的多行注释方法把实际可运行的代码注释掉又不是一个很好的方法(这种注释还是专门用来以自然语言解释代码功能较好),通过这种宏把大段的有效代码“注释”起来,可以随时开关某些代码段,在代码测试时是一个不错的方法。
这是 3 种比较少见的用法,## 代表连接,# 代表转换为字符串(加双引号),#@ 则代表转换为字符(加单引号)。比如:
#define CON(x, y) x##y #define STR(x) #x #define CHR(x) #@x CON(123, 456) //123456 STR(hello123) //"hello123" CHR(1) //'1'
不过经过我的实验,#@ 这个宏在 GCC 下是不被识别的,但在 MSDN 网站上却有相关解释。经过进一步的调查我发现,该宏是针对 MSVC 特有的,换句话说, 这是微软独家的,所以开发跨平台代码时应避免使用。鉴于在 C 标准中并没有明确规定宏实现的方式,出现这种情况也在情理之中。如果要在 gcc 下实现 #@ 宏的功能,可以尝试截取 #x 宏的首个字符,比如 ((#@x)[0])。
## 和 # 两个宏在宏的嵌套中需要注意,如果宏的实参中带有 # 或 ##,则该实参不再展开。比如:
#define CON(x, y) x##y #define STR(x) #x #define XCON(x,y) CON(x,y) CON(e4, CON(ew,ji)) //e4CON(ew,ji) CON(x, STR(123)) //xSTR(123) XCON(e4, XCON(ew,ji)) //e4ewji
在 gcc 4.8.2 中测试时,CON(CON(x,y),z) 并不能通过,而 CON(x,CON(y,z)) 就可以通过。可能又与不同编译器的具体实现有关吧。此种偏僻的问题,不该深究。
【本文参考】“#if 0/#if 1 … #endif”的作用
你也许不知道的#define用法
#define cat(x,y) x##y cat(cat(1,2),3)为什么不能编译成123
关于C里面宏替换的问题
Using MSVC preprocessor ‘charizing’ operator in Clang