为什么这些连续的宏替换不会导致错误?

Aha*_*sir 3 c macros

该程序将输出设为5.但是在替换所有宏之后,它将导致--5.这应该导致编译错误,试图减少5.但它编译并运行良好.

#include <stdio.h>
#define A -B
#define B -C
#define C 5

int main()
{
    printf("The value of A is %d\n", A); 
    return 0;
} 
Run Code Online (Sandbox Code Playgroud)

为什么没有错误?

chq*_*lie 7

以下是编译语句的步骤printf("The value of A is %d\n", A);:

  • 词法分析器产生预处理标记printf,(,"The value of A is %dn",,,A,);.
  • A为展开至所述2个令牌的宏-B.
  • B也是一个宏,并扩展到-C.
  • C又是一个宏,并扩展到5.
  • 然后将标记转换为C标记,从而为预处理标记产生错误,这些标记不会转换为正确的C标记(例如0a).在此示例中,令牌是相同的.
  • 编译器根据到C语法解析所产生的序列:printf,(,"The value of A is %d\n",,,-,-,5,),;匹配的函数调用printf以2个参数:一个格式字符串和一个常量表达式- - 5,其计算结果为5在编译时.
  • 因此代码相当于printf("The value of A is %d\n", 5);.它会产生输出:

    The value of A is 5
    
    Run Code Online (Sandbox Code Playgroud)

这个宏序列扩展为标记,而不是严格的字符序列,因此A不会扩展为--5,而是扩展为- -5.好的C编译器在将源预处理到文本输出时会插入额外的空间,以确保生成的文本在重新分析时产生相同的标记序列.但请注意,C标准没有说明文本输出的预处理,它只指定预处理作为解析阶段之一,并且编译器在预处理到文本输出时不会引入潜在的副作用,这是一个实现质量问题.

有一个单独的功能可以将令牌组合到预处理器中称为令牌粘贴的新令牌中.它需要一个特定的操作员##,使用起来非常棘手.

另请注意,应在每个参数周围使用括号定义宏,并在整个扩展周围使用括号以防止运算符优先级问题:

#define A  (-B)
#define B  (-C)
#define C  5
Run Code Online (Sandbox Code Playgroud)