为什么预处理器不会导致两个相邻的减号为减量?

时间:2017-10-14 15:20:58

标签: c preprocessor

请考虑以下代码:

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

此处预处理应按以下方式进行:

  1. 首先应该用 -B
  2. 替换A.
  3. 然后B应该被-C替换,因此表达式导致 - C
  4. 然后C应该被替换为5因此表达式导致 - 5
  5. 因此结果表达式应该给出编译错误(左值错误)。 但正确的答案是5,输出怎么能是5?

    请帮助我。

3 个答案:

答案 0 :(得分:15)

preprocesses to(注意空格):

int main()
{
  printf("The value of A is %d\n", - -5);
  return 0;
}

预处理器会粘贴令牌,而不是字符串。除非您force token concatenation with ##,否则不会从两个相邻的--令牌中创建-

#define CAT_(A,B) A##B
#define CAT(A,B) CAT_(A,B)

#define A CAT(-,B)

#define B -C
#define C 5

int main()
{
  printf("The value of A is %d\n", A); /* A is --5 here—no space */ 
  return 0;
}

答案 1 :(得分:9)

虽然C预处理器经常感觉它在字面上进行搜索并替换代码,但预处理器实际上的工作方式有点不同。

在预处理器运行之前,源文件被拆分为预处理标记,它们是单独的文本单元。例如,单个减号不是作为字符处理,而是作为由减号组成的标记,双减号被视为包含两个减号的标记。

C预处理器启动并替换每个宏而不是宏替换的文本文本,而是替换该替换中的一系列预处理器标记。在这种情况下,预处理器用A替换A后跟B替换A,然后用减去C替换B,然后用5替换C.这里的效果是有两个一元的最小值应用于5,而不是减少运算符,即使文字搜索和替换会生成一个产生语法错误的递减运算符。

这很有趣,因为你无法在源代码中编写两个连续的减号,并将其解释为两个一元的缺点。这只能起作用,因为当预处理器将所有内容拼接在一起时,它已经知道它正在查看两个一元的缺点。然后,重新扫描生成的C代码,使其第二次被标记化。

现在,legalese:section§5.1.1.2/ 7表示在完成宏替换之后,每个预处理令牌 - 这里有两个(两个减号) - 被转换为实际的令牌,然后它们'在语法和语义上进行分析。这意味着编译器没有机会重新扫描这些令牌以将它们重新解释为单个令牌。所以这是一个奇怪的情况,在这种情况下,生成的令牌流实际上不能在不改变含义的情况下输入到源代码中。

答案 2 :(得分:0)

将结果表达式视为:

-(-(5))