C预处理器如何处理循环依赖?
我想知道C预处理器如何处理循环依赖(#defines)。 这是我的程序:
#define ONE TWO #define TWO THREE #define THREE ONE int main() { int ONE, TWO, THREE; ONE = 1; TWO = 2; THREE = 3; printf ("ONE, TWO, THREE = %d, %d, %d \n",ONE, TWO, THREE); }
这是预处理器输出。 我无法弄清楚为什么输出是这样的。 我想知道预处理器在这种情况下采取的各种步骤,以提供以下输出。
# 1 "check_macro.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "check_macro.c" int main() { int ONE, TWO, THREE; ONE = 1; TWO = 2; THREE = 3; printf ("ONE, TWO, THREE = %d, %d, %d \n",ONE, TWO, THREE); }
我在linux 3.2.0-49-generic-pae上运行这个程序,并在gcc版本4.6.3(Ubuntu / Linaro 4.6.3-1ubuntu5)中编译。
当一个预处理器macros被扩展时,这个macros的名字不会被扩展。 所以你所有的三个符号都被定义为:
ONE -> TWO -> THREE -> ONE (not expanded because expansion of ONE is in progress) TWO -> THREE -> ONE -> TWO ( " TWO " ) THREE -> ONE -> TWO -> THREE ( " THREE " )
这个行为是由C标准的第6.10.3.4节设定的(C11草案中的章节编号,尽pipe据我所知C89以后该章节的措词和编号是不变的)。 当遇到一个macros名称时,它被replace为它的定义( #
和##
预处理器操作符以及类似于函数的macros的参数)。 然后结果重新扫描更多的macros(在文件的其余部分的上下文中):
2 /如果在replace列表的扫描期间(不包括源文件的其他预处理标记)find正在replace的macros的名称,则不会被replace。 此外,如果任何嵌套replace遇到被replace的macros的名称,它不会被replace…
该条款继续说,任何由于recursion调用而未被replace的令牌都被有效地“冻结”:它将永远不会被replace:
…这些未replace的macros名预处理令牌不再可用于进一步的replace,即使它们在macros名称预处理令牌将被replace的上下文中被重新检查。
最后一句提到的情况在实践中很less出现,但这是我能想到的最简单的情况:
#define two one,two #define a(x) b(x) #define b(x,y) x,y a(two)
结果是one, two
。 two
扩大到one,two
在更换a
期间,扩展后的two
被标记为完全扩展。 随后, b(one,two)
被扩大。 这已经不是在two
人的替代的背景下,但是作为b
的第二个论点的two
已经被冻结了,所以它不再被扩大。
您的问题通过出版物ISO / IEC 9899:TC2第6.10.3.4节“重新扫描和进一步更换”第2段进行解答 在将来, 当您对规格有疑问时 , 请考虑阅读具体的说明 。
如果在扫描replace列表期间(不包括源文件的预处理标记的其余部分)find正在replace的macros的名称,则不会replace它。 此外,如果任何嵌套replace遇到被replace的macros名称,则不会被replace。 这些未replace的macros名预处理令牌不再可用于进一步replace,即使它们在其中macros名预处理令牌将被replace的上下文中稍后(重新)检查。
答案的症结在于,当预处理器find自我参照macros时,根本不会扩展它们。
我怀疑,同样的逻辑是用来防止循环定义的macros的扩展。 否则,预处理器将无限扩展。
在你的例子中,你需要在定义同名variables之前进行macros处理,所以不pipemacros处理的结果是什么,你总是打印1, 2, 3
!
这是一个首先定义variables的例子:
#include <stdio.h> int main() { int A = 1, B = 2, C = 3; #define AB #define BC //#define CA printf("%d\n", A); printf("%d\n", B); printf("%d\n", C); }
这打印3 3 3
。 有点阴险的是,取消注释#define CA
改变行printf("%d\n", B);
下面是在rici和Eric Lippert的回答中所描述的行为的一个很好的例子 ,也就是说,如果在扩展同一个macros的时候再次遇到macros名,macros名不会被重新展开。
test.c
内容:
#define ONE 1, TWO #define TWO 2, THREE #define THREE 3, ONE int foo[] = { ONE, TWO, THREE };
gcc -E test.c
输出(不包括最初的# 1 ...
行):
int foo[] = { 1, 2, 3, ONE, 2, 3, 1, TWO, 3, 1, 2, THREE };
(我会张贴这个评论,但包括在评论中的大量代码块是有点尴尬,所以我把这个社区Wiki的答案,而不是如果你觉得这将是更好的包括作为现有答案的一部分,感觉自由复制它并要求我删除这个CW版本。)