为什么这些代码块会产生不同的结果?
一些常用代码:
#define PART1PART2 works
#define STRINGAFY0(s) #s
#define STRINGAFY1(s) STRINGAFY0(s)
案例一:
#define GLUE(a,b,c) a##b##c
STRINGAFY1(GLUE(PART1,PART2,*))
//yields
"PART1PART2*"
案例二:
#define GLUE(a,b) a##b##*
STRINGAFY1(GLUE(PART1,PART2))
//yields
"works*"
案例三:
#define GLUE(a,b) a##b
STRINGAFY1(GLUE(PART1,PART2*))
//yields
"PART1PART2*"
我正在使用来自 VS.net 2005 sp1 的 MSVC++
编辑: 目前我认为预处理器在扩展宏时是这样工作的: 步骤1: - 带上尸体 - 删除## 运算符周围的任何空格 - 如果找到与参数名称匹配的标识符,则解析字符串: - 如果它在## 运算符旁边,则将标识符替换为参数的字面值(即传入的字符串) - 如果它不在## 运算符旁边,则首先对参数值运行整个解释过程,然后用该结果替换标识符。 (忽略 stringafy 单个 '#' 大小写 atm) -删除所有##运算符
第 2 步: - 获取结果字符串并将其解析为任何宏
现在,我认为所有 3 种情况都应该产生完全相同的结果字符串:
第一部分第二部分*
因此在第 2 步之后,结果应该是
作品*
但至少应该产生相同的结果。
最佳答案
情况 1 和情况 2 没有定义的行为,因为您很想将 *
粘贴到一个预处理器 token 中。根据预处理器的关联规则,这会尝试将标记 PART1PART2
(或只是 PART2
)和 *
粘合在一起。在您的情况下,这可能会无声地失败,这是未定义的可能结果之一。标记 PART1PART2
后跟 *
将不再被考虑用于宏扩展。 Stringfication 然后生成您看到的结果。
我的 gcc 在你的例子中表现不同:
/usr/bin/gcc -O0 -g -std=c89 -pedantic -E test-prepro.c
test-prepro.c:16:1: error: pasting "PART1PART2" and "*" does not give a valid preprocessing token
"works*"
所以总结一下你的案例 1 有两个问题。
- 粘贴两个没有结果的标记 在有效的预处理器 token 中。
##
运算符的求值顺序
在情况 3 中,您的编译器给出了错误的结果。应该
- 评估论点
STRINGAFY1
- 要做到这一点,它必须扩展
GLUE
GLUE
结果为PART1PART2*
- 必须再次展开
- 结果是
有效*
- 然后传递给
STRINGAFY1
关于c++ - 试图了解 C 预处理器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3279014/