简体   繁体   English

C中级联宏的规则

[英]Rules for cascading macros in C

I cannot find rules for C preprocessor that handle the case below. 我无法找到处理下面案例的C预处理器的规则。 If you assume a straight substitution this case should not even compile because a=--1 . 如果你假设一个直接替换,这种情况甚至不应该编译,因为a=--1 But if you assume substitution with parenthesis then a=-(-1) = 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;
}

Preprocessing is the phase which precede compilation it generates a preprocessing translation unit which will be the input for compiler. 预处理是编译之前的阶段,它生成一个预处理转换单元,它将作为编译器的输入。

Some of those steps in its process are ( From C99 5.1.1.2 ): 其过程中的一些步骤是( 来自 C99 5.1.1.2 ):

  1. The source file is decomposed into preprocessing tokens . 源文件被分解预处理令牌 (...) (......)

  2. Preprocessing directives are executed, macro invocations are expanded , (...) 执行预处理指令, 扩展宏调用 ,(...)

As you can see Tokenization precede macro invocation so -ALPHA will be considered as 2 separate preprocessing tokens (*ie - and ALPHA 1 ) and not as you thought by 2 preprocessing token --1 ( -- and 1 ) 正如您所见,Tokenization 宏调用之前,因此-ALPHA将被视为2个单独的预处理令牌(* ie -ALPHA 1 ),而不是您认为的2个预处理令牌--1--1

After that in rule 7: 在第7条之后:

  1. White-space characters separating tokens are no longer significant . 分隔标记 的空白字符不再重要 Each preprocessing token is converted into a token. 每个预处理令牌都转换为令牌。

So the compiler will get tokens and ignore whitespaces. 因此编译器将获得令牌并忽略空格。

If you generate the preprocessing file with gcc -E whitespaces have no significance and those you are seeing are only for formatting to user and cannot reflect the real internal behavior of CPP. 如果使用gcc -E生成预处理文件gcc -E空格没有任何意义,而您所看到的仅用于格式化为用户,并且无法反映CPP的实际内部行为。

From GCC CPP 5.4.0 1.3 : 来自GCC CPP 5.4.0 1.3

Tokens do not have to be separated by white space , but it is often necessary to avoid ambiguities (...) 令牌不必用空格分隔 ,但通常需要避免歧义 (...)

Once the input file is broken into tokens, the token boundaries never change , except when the '##' preprocessing operator is used to paste tokens together 一旦输入文件被分解为令牌, 令牌边界永远不会改变 ,除非使用'##'预处理操作符将令牌粘贴在一起

The compiler does not re-tokenize the preprocessor's output . 编译器不会重新标记预处理器的输出 Each preprocessing token becomes one compiler token. 每个预处理令牌都成为一个编译器令牌。

Summarizing: 总结:

If you write -ALPHA => tokens are: 如果你写-ALPHA =>令牌是:

  • - punctuator - binary minus sign -标点符号 - 二进制减号

  • - punctuator - binary minus sign -标点符号 - 二进制减号

  • 1 constant - integer constant 1常数 - 整数常量

If you write --1 => tokens are: 如果你写--1 =>令牌是:

  • -- punctuator - Decrement operator -- punctuator - 递减运算符

  • 1 constant - integer constant 1常数 - 整数常量

Decrement operator should not be used with constant that's why you get error in this case during compilation. 递减运算符不应该与常量一起使用,这就是编译期间在这种情况下出错的原因。


1 : ALPHA identifier will be replaced (in phase 4) by two preprocessing tokens - and 1 already identified in macro definition 1: ALPHA标识符将两个预处理标记替换 (在第4阶段) -并且在宏定义中标识 1

This is how your program looks after pre-processing is completed. 这是您的程序在预处理完成后的样子。

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

You can view this output using -E option with gcc . 您可以使用-E选项和gcc一起查看此输出。

It is definitely not --1 . 绝对不是--1 Notice the extra space. 注意额外的空间。

First thing you have to understand that C Preprocessors is not a part of compilation process. 首先要了解C预处理器不是编译过程的一部分。 It's just the substitution process which tells the compiler to do required pre-processing before the actual compilation. 它只是替换过程,它告诉编译器在实际编译之前进行必要的预处理。

To understand much you have to read the Macro Pitfalls . 要了解很多,你必须阅读宏观陷阱

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM