为什么在此代码中未定义X?

时间:2014-04-18 19:40:40

标签: c c-preprocessor

#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;。

4 个答案:

答案 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需要是变量名。 它不是,因此错误信息。