C

时间:2017-02-11 17:55:50

标签: c c-preprocessor

我无法找到处理下面案例的C预处理器的规则。如果你假设一个直接替换,这种情况甚至不应该编译,因为a=--1。但是如果你假设用括号替换a=-(-1) = 1

#include <stdio.h>
#define  ALPHA -1
#define  BETA -ALPHA
int main(void) {
    int a = BETA;
    int b = -ALPHA; // this compiles too, why? b = --1
    printf("%d\n",a); // 1
    return 0;
}

3 个答案:

答案 0 :(得分:2)

预处理是编译之前的阶段,它会生成一个预处理转换单元,它将作为编译器的输入。

其过程中的部分步骤是( From C99 5.1.1.2 ):

  
      
  1. 源文件已分解预处理令牌。 (...)

  2.   
  3. 执行预处理指令,扩展宏调用,(...)

  4.   

正如您所见,标记化宏调用之前,因此-ALPHA将被视为2个单独预处理标记(* ie -和{{ 1}} 1 )而不是你想象的2预处理令牌ALPHA--1--

在规则7之后:

  
      
  1. 空格字符分隔标记不是更长显着。   每个预处理令牌都转换为令牌。
  2.   

因此编译器将获得令牌并忽略空格。

如果使用1生成预处理文件,则空格没有任何意义,而您所看到的仅用于格式化为用户,并且无法反映CPP的实际内部行为。

来自 GCC CPP 5.4.0 1.3

  

代币不必用空格分隔,但它经常是   必要的以避免含糊不清(...)

     

一旦输入文件被分解为令牌,令牌边界永远不会   更改,除非使用'##'预处理运算符进行粘贴   一起代币

     

编译器不会重新标记预处理器的输出。每   预处理令牌成为一个编译器令牌。

汇总:

如果你写gcc -E =&gt;代币是:

  • -ALPHA标点符号 - 二进制减号

  • -标点符号 - 二进制减号

  • -常量 - 整数常量

如果你写1 =&gt;代币是:

  • --1标点符号 - 递减运算符

  • --常量 - 整数常量

递减运算符不应该与常量一起使用,这就是编译期间在这种情况下出错的原因。

1:1标识符被替换(在第4阶段)由两个预处理标记ALPHA- 已识别< / strong>在宏定义中

答案 1 :(得分:1)

这是预处理完成后程序的样子。

int main(void) {
    int a = - -1;
    int b = - -1;
    printf("%d\n",a);
    return 0;
}

您可以使用-E选项gcc来查看此输出。

绝对不是--1。注意额外的空间。

答案 2 :(得分:0)

首先要了解C预处理器不是编译过程的一部分。它只是替换过程,它告诉编译器在实际编译之前进行必要的预处理。

要了解更多,您必须阅读Macro Pitfalls