为什么这些代码块会产生不同的结果?

一些常用代码:

#define PART1PART2 works
#define STRINGAFY0(s) #s
#define STRINGAFY1(s) STRINGAFY0(s)

情况1:

#define GLUE(a,b,c) a##b##c  
STRINGAFY1(GLUE(PART1,PART2,*))
//yields
"PART1PART2*"

案例2:

#define GLUE(a,b) a##b##*
STRINGAFY1(GLUE(PART1,PART2))
//yields
"works*"

案例3:

#define GLUE(a,b) a##b
STRINGAFY1(GLUE(PART1,PART2*))
//yields
"PART1PART2*"

我正在使用 VS.net 2005 sp1 中的 MSVC++

编辑:目前我认为预处理器在扩展宏时是这样工作的:步骤1:- 拿起身体 - 删除##运算符周围的所有空格 - 解析字符串,如果发现标识符与参数的名称匹配:-如果它位于 ## 运算符旁边,则将标识符替换为参数的文字值(即字符串传递给) - 如果它不在##运算符旁边,请先在参数的值上运行整个说明过程,然后用该结果替换标识符。(忽略Stringafy单#'case atm) - 删除所有##操作员

第2步:- 获取结果字符串并解析它以查找任何宏

现在,我相信所有 3 种情况都应该产生完全相同的结果字符串:

第 1 部分第 2 部分*

因此在步骤 2 之后,应该会导致

作品*

但至少应该导致同样的结果。

有帮助吗?

解决方案

情况 1 和 2 没有定义的行为,因为您很想粘贴 * 到一个预处理器标记中。根据预处理器的关联规则,这要么尝试将标记粘合在一起 PART1PART2 (要不就 PART2) 和 *. 。在你的情况下,这可能会默默地失败,这是当事情未定义时可能的结果之一。代币 PART1PART2 其次是 * 然后将不再考虑进行宏扩展。然后字符串化会产生您看到的结果。

我的海湾合作委员会在你的例子中表现不同:

/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 有两个问题。

  • 粘贴两个代币不会导致有效的预处理器令牌。
  • 的评估顺序 ## 操作员

在情况 3 中,您的编译器给出了错误的结果。它应该

  1. 评估参数STRINGAFY1
  2. 要做到这一点,它必须扩大 GLUE
  3. GLUE 结果是 PART1PART2*
  4. 必须再次扩展
  5. 结果是 works*
  6. 然后传递给STRINGAFY1

其他提示

它正在做什么你告诉它要做的事情。第一个和第二个采取符号名称传递并将它们粘贴到一个新的符号中。第三个是2个符号并粘贴它们,然后你自己把*放在字符串中(最终会评估为其他东西。)

结果是什么问题?你期望得到什么?这一切似乎都在工作,因为我期待它。

然后当然是你为什么和任何像这样的符号令人营地一起玩的问题?:)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top