为什么这些连续的宏替换不会导致错误? [英] Why these consecutive macro replacements do not result in an error?
问题描述
该程序的输出为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;
}
为什么没有错误?
以下是编译语句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
的函数调用:格式字符串和常量表达式-
-
5
,在编译时其结果为5
.
因此, -
该代码等效于
printf("The value of A is %d\n", 5);
.它将产生输出:The value of A is 5
此宏序列被扩展为记号,严格来说不是字符序列,因此,A
不能扩展为--5
,而可以扩展为- -5
.好的C编译器在将源预处理为文本输出时会插入额外的空间,以确保所生成的文本在重新解析时产生相同的标记序列.但是请注意,C标准并未提及对文本输出进行预处理的任何内容,它仅将预处理指定为解析阶段之一,并且对于编译器而言,在对文本输出进行预处理时不引入潜在的副作用是实现质量的问题.>
还有一个单独的功能,可以将令牌组合成预处理器中的新令牌,称为令牌粘贴.它需要特定的运算符##
,使用起来很棘手.
还请注意,应在宏的每个参数周围加上括号,并在整个扩展名之间加上括号,以防止出现运算符优先级问题:
#define A (-B)
#define B (-C)
#define C 5
This program gives output as 5. But after replacing all macros, it would result in --5
. This should cause an compilation error, trying to decrement the 5
. But it compiles and runs fine.
#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;
}
Why is there no error?
Here are the steps for the compilation of the statement printf("The value of A is %d\n", A);
:
- the lexical parser produces the preprocessing tokens
printf
,(
,"The value of A is %dn"
,,
,A
,)
and;
. A
is a macro that expands to the 2 tokens-
andB
.B
is also a macro and gets expanded to-
andC
.C
is again a macro and gets expanded to5
.- the tokens are then converted to C tokens, producing errors for preprocessing tokens that do not convert to proper C tokens (ex:
0a
). In this example, the tokens are identical. - the compiler parses the resulting sequence according to the C grammar:
printf
,(
,"The value of A is %d\n"
,,
,-
,-
,5
,)
,;
matches a function call toprintf
with 2 arguments: a format string and a constant expression-
-
5
, which evaluates to5
at compile time. the code is therefore equivalent to
printf("The value of A is %d\n", 5);
. It will produce the output:The value of A is 5
This sequence of macros is expanded as tokens, not strictly a sequence of characters, hence A
does not expand as --5
, but rather as - -5
. Good C compilers would insert an extra space when preprocessing the source to textual output to ensure the resulting text produces the same sequence of tokens when reparsed. Note however that the C Standard does not say anything about preprocessing to textual output, it only specifies preprocessing as one of the parsing phases and it is a quality of implementation issue for compilers to not introduce potential side effects when preprocessing to textual output.
There is a separate feature for combining tokens into new tokens in the preprocessor called token pasting. It requires a specific operator ##
and is quite tricky to use.
Note also that macros should be defined with parentheses around each argument and parentheses around the whole expansion to prevent operator precedence issues:
#define A (-B)
#define B (-C)
#define C 5
这篇关于为什么这些连续的宏替换不会导致错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!