c语言里的宏(翻译) 5
原文在这里
字符化
有的时候,你也会想把一个宏参数直接转化成一个字符常量。你想要在某个字符串中插入宏参数,期待它会简单的被替换成字符常量,想法不错,但不可能。不过你可以用"#"预处理操作符。当一个宏参数前置"#"时,预处理器就会把宏参数符号替换成跟宏参数符号相同的字符常量。与常规参数替换不同的是,该类转化不叫宏展开,而叫"字符化"。
把一个宏参数混在字符串内部,然后字符化它,这种操作是不可能成功的。相反,你应该写一系列独立的字符常量,并把宏参数夹在各字符常量之间。预处理器会把宏参数字符化,然后c编译器会把所有独立的字符串合成一条长字符串。
下面是一个使用了字符化的宏的例子
#define WARN_IF(EXP) \ do { if (EXP) \ fprintf (stderr, "Warning: " #EXP "\n"); } \ while (0) WARN_IF (x == 0); ==> do { if (x == 0) fprintf (stderr, "Warning: " "x == 0" "\n"); } while (0);
参数EXP一次在if语句里使用,还有一次在fprintf函数里被字符化。如果x也是一个宏,在if语句里会继续展开,但是在字符化时不会。
do while(0)循环是一个小伎俩,使得WARN_IF(arg);这种写法成为可能,否则的话宏内容里的if语句会把正常的c语言流程搞糟。参看大括号对齐。
c里面的字符化可不是在参数两边加引号这么简单,它还会把各类特殊字符转义,以便得到一个合法的c字符串。所以,字符串p = “foo\n”当成参数传入宏,字符化后的结果是"p = \"foo\\n\";"。但是本来就是特殊字符的那些还是保留原样,比如字符'\n’字符化后是"\n"。
所有前置和后置的空格都会被忽略。所有在中间的空格都会被转化成一个空格。注释早在执行字符化之前一百万年就已经被预处理器干掉了,所以字符化结果里绝不会有注释。
想把一个宏参数转成字符常量(而不是字符串常量),是没可能做到的。
如果你想看一个宏展开后是什么样子,可以用两级宏:
#define xstr(s) str(s) #define str(s) #s #define foo 4 str (foo) ==> "foo" xstr (foo) ==> xstr (4) ==> str (4) ==> "4"