为什么这些连续的宏替换不会导致错误? [英] Why these consecutive macro replacements do not result in an error?

查看:116
本文介绍了为什么这些连续的宏替换不会导致错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

该程序的输出为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 - and B.
  • B is also a macro and gets expanded to - and C.
  • C is again a macro and gets expanded to 5.
  • 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 to printf with 2 arguments: a format string and a constant expression - - 5, which evaluates to 5 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆