#include <stdio.h>
#define X (Y+4)
#define Y (X+3)
int main(void) {
printf("%d\n",4*X+2);
return 0;
}
错误:未定义的符号&#39; X&#39;。
答案 0 :(得分:5)
宏扩展不会递归地重新扩展宏名称。
引用C标准:
如果在此扫描期间找到要替换的宏的名称 替换列表(不包括源文件的其余部分 预处理令牌),它没有被替换。此外,如果有任何嵌套 替换遇到被替换的宏的名称,它不是 更换。这些未替换的宏名称预处理标记是否定的 更长的可用于进一步更换,即使它们以后 (重新)在宏名称预处理令牌的上下文中进行检查 否则就会被取代。
X
扩展为(Y + 4)
。然后,预处理器会尝试展开Y
,但由于Y
的扩展指的是X
,因此它不会再次展开它,只留下X
。
此规则避免了宏扩展中的无限递归(如果此规则不存在,那么就是您在示例中所拥有的)。
宏扩展后,行
printf("%d\n",4*X+2);
解析为:
printf("%d\n",4*((X+3) +4)+2);
由于X
尚未以预处理器外部可见的方式定义,因此存在编译时错误。
答案 1 :(得分:3)
因为X由Y定义,它也重用X来定义自己。它是一个循环参考。
答案 2 :(得分:2)
如果您有gcc,请使用-E
开关并在预处理后查看该文件:
>type example.c
//#include <stdio.h>
extern int printf(const char *s, ...);
#define X (Y+4)
#define Y (X+3)
int main(void) {
printf("%d\n",4*X+2);
return 0;
}
>gcc -Wall -E example.c
# 1 "example.c"
# 1 "<command-line>"
# 1 "example.c"
extern int printf(const char *s, ...);
int main(void) {
printf("%d\n",4*((X+3)+4)+2); // see X?
return 0;
}
>
答案 3 :(得分:1)
预处理器宏X
扩展为(Y+4)
。这包含另一个预处理器宏Y
,因此它扩展为((X+3)+4)
。这又包含预处理器宏X
。
C预处理器的一个功能是阻止递归:如果宏的名称在扩展期间出现,则它将保持不变。这允许像
这样的定义#define f(x) (LOG("f called"), f(x))
(不太常见,但可能)。 (如果它不适用于该功能,预处理器将在许多情况下永远循环,例如这个,这不会有用。)
此时,预处理器已完成其工作,因此X
需要是变量名。
它不是,因此错误信息。