Macros 为什么这个宏被替换为20而不是10?
当我只运行预处理器时,输出文件包含20个 然而,据我所知,预处理器只是进行文本替换。这就是我认为正在发生的事情(这显然是错误的,但idky):Macros 为什么这个宏被替换为20而不是10?,macros,c-preprocessor,Macros,C Preprocessor,当我只运行预处理器时,输出文件包含20个 然而,据我所知,预处理器只是进行文本替换。这就是我认为正在发生的事情(这显然是错误的,但idky): NUM被定义为10 因此,在第2行中,NUM替换为10。现在我们有了“定义FOO 10” NUM未定义 NUM被重新定义,现在是20 FOO根据第2行进行更换,第2行在第4行重新定义之前,第10行 所以我认为输出应该是10而不是20。有什么能解释它哪里出错了吗?文本替换是在使用宏的地方进行的,而不是在编写\define的地方。在您使用FOO时,它将FOO
所以我认为输出应该是10而不是20。有什么能解释它哪里出错了吗?文本替换是在使用宏的地方进行的,而不是在编写
\define
的地方。在您使用FOO
时,它将FOO
替换为NUM
,NUM
当前定义为20
:
1. #define NUM 10
2. #define FOO NUM
3. #undef NUM
4. #define NUM 20
5.
6. FOO
预处理器将用NUM
替换它,然后将NUM
替换为它当前的定义,即20
最初的四行相当于:
FOO
<> P11 > C11标准(和C和C++的其他版本,类似地说):
格式为#define identifier replacement list new line
的预处理指令定义了一个类似对象的宏,该宏使宏名称的每个后续实例都被构成该指令其余部分的预处理标记的替换列表所替换。然后重新扫描替换列表以获得更多宏名称,如下所示
不过,它在另一部分也提到了这一点(感谢rici指出这一点)
除非另有说明,否则预处理指令中的预处理令牌不受宏扩展的约束
因此,在另一个#define
指令中找到的宏名称的后续实例实际上是而不是替换的
您的行#define FOO NUM
定义了当稍后找到令牌FOO
时(在另一个#define
指令之外!),它将被令牌NUM
替换
替换令牌后,将进行重新扫描,如果NUM
本身是一个宏,则此时将替换NUM
。(如果任何NUM
展开为包含宏的内容,则该内容将展开,依此类推)
所以你的步骤顺序实际上是:
NUM
定义为10
FOO
定义为NUM
NUM
未定义并重新定义为20
FOO
扩展为NUM
NUM
扩展到20
这种行为可以在另一种常见的预处理器技巧中看到,即将宏的定义值转换为字符串:
#define FOO NUM
#define NUM 20
如果我们编写了put(STR(NUM))
,那么输出将是NUM
10
的输出是可能的,因为与以前一样,这里的第二个#define
实际上没有向外扩展STR
。因此,该代码中的步骤顺序是:
STR(X)
定义为#X
STR\u宏(X)
定义为STR(X)
NUM
定义为10
stru宏
和NUM
都已展开;结果为put(STR(10))代码>
STR(10)
被扩展为“10”
为了从标准中收集所有相关的规范,我从注释线程中提取了这些信息,并根据草案N45 27添加了C++区号,两个标准中的规范文本是相同的。这些标准在这个问题上是绝对明确的
#define
预处理器指令不进行宏替换
(C11×6.10±7;C++16〔CPP〕6〕:预处理指令中的预处理标记不受宏扩展,除非另有说明。< /P>
(C11×6 .10 3,9;C++16.3〔CPP〕替换〕9)表格
的预处理指令#定义标识符替换列表新行
定义一个类似对象的宏,该宏使宏名称的每个后续实例被构成指令其余部分的预处理标记的替换列表替换。然后重新扫描替换列表以获得更多宏名称,如下所示
#define
后面的行开始,一直处于活动状态,直到宏名称的#unde
或文件结尾
(C11<61.3.5,1;C++16.3.5[CPP.Simult])1,宏定义持续(独立于块结构),直到遇到相应的<代码>“unDEF指令”或(如果没有遇到)直到预处理翻译单元结束为止。在翻译阶段4之后,宏定义没有意义
#define STR(X) #X
#define STR_MACRO(X) STR(X)
#define NUM 10
puts( STR_MACRO(NUM) ); // output: 10
我们看到第1行中的NUM
的宏定义一直持续到第3行。这些行中没有可替换的文本,因此从未使用该定义;因此,该计划实际上与以下内容相同:
#define NUM 10
#define FOO NUM
#undef NUM
#define NUM 20
FOO
在这个程序的第三行,有一个活动的定义,用于FOO
,具有替换列表NUM
,以及NUM
,具有替换列表20
。FOO
被替换为其替换列表,使其成为NUM
,然后再次扫描
#define FOO NUM
#define NUM 20
FOO