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

Ris*_*hal 12 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;
}
Run Code Online (Sandbox Code Playgroud)

这里的预处理应该按以下方式进行:

  1. 首先应该用-B替换A.
  2. 则B应被替换为这样-C表达所得成--C
  3. 然后C应该被替换为5因此表达式导致--5

因此,结果表达式应该给出编译错误(左值错误).但正确的答案是5,输出怎么能是5?

请帮帮我.

PSk*_*cik 15

预处理到(注意空间):

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

预处理器粘贴令牌,而不是字符串.除非您强制使用以下标记连接,否则它不会创建--两个相邻的-标记:##

#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;
}
Run Code Online (Sandbox Code Playgroud)

  • @ user3290550 [C语法](http://www.quut.com/c/ANSI-C-grammar-y-1999.html)将其简单地解释为` - ( - (5))`.它被解析得很好. (2认同)
  • 这只是gcc的一个人工制品,它对预处理的令牌流进行后处理,以便创建一个文本流,然后将其反馈到编译器中.预处理器本身(转换阶段4)产生一系列令牌,这些令牌将被馈送到以下转换阶段.(从技术上讲,它产生了一个令牌和空白流,但是空白并不重要,我们几乎立即就丢弃了.) (2认同)

tem*_*def 9

虽然C预处理器通常感觉它实际上是在搜索和替换代码,但预处理器实际上有点不同.

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

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

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

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


noe*_*cus 0

将结果表达式想象为:

-(-(5))
Run Code Online (Sandbox Code Playgroud)