c - 宏替换列表重新扫描替换
问题描述
我正在阅读关于宏替换的标准 N1570,并误解了6.10.3.4
.
1 在替换列表中的所有参数都已被替换并且 # 和 ## 处理已经发生后,所有 placemarker 预处理标记都将被删除。然后重新扫描生成的预处理标记序列以及源文件的所有后续预处理标记,以替换更多宏名称
所以毕竟解决#
了##
我们重新扫描替换列表。但第 2 节规定:
2 如果在替换列表的扫描过程中找到被替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。此外,如果任何嵌套替换遇到被替换的宏的名称,它不会被替换。
这在我看来很矛盾。那么在重新扫描中可能有什么样的替换?我尝试了以下示例:
#define FOOBAR(a, b) printf(#a #b)
#define INVOKE(a, b) a##b(a, b)
int main() {
INVOKE(FOO, BAR); //expands to printf("FOO" "BAR")
}
所以INVOKE(FOO, BAR)
展开到FOOBAR(FOO, BAR)
的替换后##
。FOOBAR(FOO, BAR)
然后重新扫描替换列表。但是该部分2.
指定要替换的宏的名称 ( FOOBAR
) 已找到(是的,已在上面定义)它没有被替换(但实际上已被替换,如演示中所示)。
你能澄清一下这个措辞吗?我错过了什么?
解决方案
被替换的(原始)宏不是FOOBAR
,而是INVOKE
. 当您扩展INVOKE
并找到FOOBAR
时,您FOOBAR
会正常扩展。但是,如果INVOKE
在展开时发现了INVOKE
,则不再展开。
让我们看下面的代码:
#define FOOBAR(a, b) printf(#a #b)
#define INVOKE(a, b) e1 a##b(a, b)
int main() {
INVOKE(INV, OKE);
}
我e1
在扩展中添加了 ,INVOKE
以便能够可视化发生了多少扩展。预处理的结果main
是:
e1 INVOKE(INV, OKE);
这证明了INVOKE
在重新扫描时扩展了一次,而不是再次扩展。
推荐阅读
- sql-server - 将子查询转换为 CTE
- python-3.x - 每个用户的 Django 文件上传
- laravel - 在apache中禁用缓存
- video - ffmpeg 在视频上淡入淡出多个图像
- javascript - Node.js 从 php 中获取价值
- javascript - 模块内的 addEventListener 问题
- c++ - 时间:2019-05-10 标签:c++scrabble score search for a word
- bash - 如何使用一个命令的输出作为另一个命令的 bash 完成
- laravel - Laravel keyby 按日期
- html - Background image won't show via URL (HTML & CSS)