c语言里的宏(翻译) 6

原文在这里

连接

在宏展开过程中把两个符号连接在一起的特性往往会很有用。我们管这种特性叫符号粘贴或者符号连接。"##" 就是用于符号连接的预处理操作符。当一个宏展开后, "##" 两边的符号就会被组合成一个,然后该组合后的符号会替换"##"两边的符号以及"##"本身。通常情况下"##"两边的符号都会是标识符,或者一边是标识符,一边是预处理号。粘贴之后,一个更长的标识符就被生成了。这不是唯一有效的情况,把两个数字粘贴成一个数字也是可以的(比如1.5 或者 e3)。同样,多字符的操作符比如+=也可以通过粘贴生成。

但是,若两个符号粘贴后不是一个合法的字符,那么他们就不能被粘在一起。比如说,你不能把x和+粘在一起。如果你一定要这么做,预处理器会发出一个警告然后把两个符号都发射出来。符号两边是否需要有空格在标准里未定义。你经常可以在一些复杂的宏里发现一些没必要的"##"。如果编译器在这种情况下发出警告,一般来讲你可以简单的把"##"去掉就行。

"##"两边的符号都可以来自宏内容,这种情况下你也可以在一开始就把他们写成一个符号。最常见的使用"##"的场合是其中的一个符号或者两个符号都是宏参数。如果"##"两边的符号中有一个是宏参数,在"##"执行前,它会被实际内容替代。在字符化里,实际内容不会在宏展开前被替换。如果参数为空,"##"什么效果也没有。

有个事项必须要牢记:把注释替换成空格这件事,c语言的预处理器会在在做任何事情前完成。所以,你不能指望连接'/' 和 '*' 来生成一个注释。你可以在"##"两边放无数的空格,包括注释在内。你也可以在宏参数里写注释。但是,"##"出现在宏内容的两端是非法的。

考虑一段c代码用于解释命令。我们可能需要一个命令名表,或者一个包含一下结构内容的数组:

     struct command
     {
       char *name;
       void (*function) (void);
     };
     
     struct command commands[] =
     {
       { "quit", quit_command },
       { "help", help_command },
       ...
     };
每一个命令里,名字都出现了两次,一次在字符串里,一次在函数名里。这样的程序不够“干净”。一个把命令名当参数的宏可以有效的解决该类问题。字符常量可以用字符化生成,函数名可以用字符粘贴'_command’来生成。以下是完成后的代码
     #define COMMAND(NAME)  { #NAME, NAME ## _command }
     
     struct command commands[] =
     {
       COMMAND (quit),
       COMMAND (help),
       ...
     };
posted @ 2008-11-20 19:27  gussing  阅读(571)  评论(0编辑  收藏  举报