C/C++宏嵌套替换逻辑

2024-01-10

我正在尝试实现 C/C++ 兼容的宏处理。我可以正确处理许多极端情况,包括此处讨论的情况:了解宏间接扩展自身时 C 预处理器的行为 https://stackoverflow.com/questions/66593868/understanding-the-behavior-of-cs-preprocessor-when-a-macro-indirectly-expands-i.

然而,有一个极端的情况,我从 gcc 和 clang 得到了不同的答案,所以我显然是错误的。该代码与此处讨论的情况类似:我们可以有递归宏吗? https://stackoverflow.com/questions/12447557/can-we-have-recursive-macros

#define ID(arg) arg
#define EMPTY
#define NOEXPAND(macro) macro EMPTY
#define F_AGAIN() F
#define F() f NOEXPAND(F_AGAIN)()()

ID(F())

I get f F (),但是 gcc/clang 输出f f F_AGAIN ()()。我的逻辑是每个令牌f NOEXPAND(F_AGAIN)()() has F在其“隐藏集中”,并且您永远无法从令牌的隐藏集中删除元素。

In 我们可以有递归宏吗? https://stackoverflow.com/questions/12447557/can-we-have-recursive-macros,最相关的答案谈论将宏绘制为蓝色而不是隐藏集,但我找不到任何关于其工作原理的完整描述。因此,我正在关注戴夫·普罗瑟的 https://www.spinellis.gr/blog/20060626/算法,它解释了隐藏集方面的 cpp 行为。我认为这就是编译器在实践中所做的。

我的问题:我是否误解了 Prosser 的算法,或者我应该实现不同的算法?现代 C 预处理器的行为是否有记录?语言规范本身在这个问题上过于模糊。


好吧,我想我已经弄清楚发生了什么事。编译器不实现 Prosser 的算法,就这样。尽管普罗瑟的算法确实解决了特定的问题已知缺陷 http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268在语言规范中,它没有解释实际编译器扩展宏的方式。

似乎有两种禁用位在起作用,而不是隐藏集:每个宏禁用位和每个令牌禁用位。

宏的每个宏禁用位M在重新扫描阶段设置M正在扩容,一旦扩容就会被清除M做完了。

如果在任何时候M被禁用预处理器处理一个实例M(无论语法上是否对扩展有效),它标记了特定的M令牌已禁用。编译器在禁用令牌时不仅会避免扩展令牌,而且还会在任何上下文中永久禁用对令牌扩展的任何考虑,即使在之后M的扩展已经完成。

让我们看一些更简单的例子:

#define ID(arg) arg
#define LPAREN (

#define F_AGAIN() F
#define F() f F_AGAIN LPAREN)()

F()         // => f F_AGAIN ()()
ID(F())     // => f f F_AGAIN ()()
ID(ID(F())) // => f f f F_AGAIN ()()

#define G() g G LPAREN)()

G()         // => g G ()()
ID(G())     // => g G ()()
ID(ID(G())) // => g G ()()

首先考虑一下扩张过程中发生了什么G()。它扩展到令牌列表g G LPAREN)()并且在重新扫描期间,G该令牌列表中的内容已永久禁用。现在,无论您因传递令牌列表而重新扫描多少次ID, the G永远无法扩展。

接下来考虑发生了什么F()。它扩展到令牌列表f F_AGAIN LPAREN)()。在重新扫描期间,这会扩展为f F_AGAIN ()()。因为F_AGAIN当前不是禁用的宏,这些输出标记都不会被禁用。所以现在在任何重新扫描ID macro, F_AGAIN会被扩展一次,也会导致F扩大一次。

在这种背景下,实际上可以理解语言规范 https://timsong-cpp.github.io/cppwp/n4861/cpp.rescan#3:

如果在替换列表扫描期间找到要替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。 此外,如果任何嵌套替换遇到被替换的宏的名称,则不会替换它。 这些未替换的宏名称预处理标记不再可用于进一步替换,即使稍后在宏名称预处理标记本来会被替换的上下文中(重新)检查它们也是如此。

我猜想与我的直觉相混淆的部分是“它没有被替换”听起来如此无害——特别是在宏无论如何都不会被替换的上下文中,例如因为它是一个类似函数的宏,后面没有一个开放括号(。然后,“令牌不再可用于进一步替换”中的被动语态听起来像是只是在描述前一句话的结果,而规范的真正含义是“编译器主动毒害该令牌并禁止其再次扩展” ”。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C/C++宏嵌套替换逻辑 的相关文章

随机推荐

  • zig 创建了一个 C 库,但 C 无法使用

    我可以让 Zig 创建一个 C 库 但是当我尝试从 C 程序中使用所述库时 它无法找到所包含函数的定义 我的图书馆定义 const std import std export fn removeAll name const u8 len u
  • 使用 prerender-spa-plugin 时如何加载 Vuetify?

    当我们在开发模式下运行 Vuetify 应用程序时 使用npm run dev 工作正常 然而 当我们使用prerender spa plugin Vuetify CSS 文件正确加载 但所有 JavaScript 组件都不起作用 即单击按
  • 如何在编辑模式下在 UITableView 中添加额外的单元格?

    您知道在表格进入编辑模式后如何让某些单元格出现在表格视图中吗 就像您编辑联系人时 通讯录 iPhone 应用程序所做的那样 也许我错了 但是在编辑联系人时 看起来像是使用了分组的 UITableView 我试过这个 self tableVi
  • Hg 存储库中的 git 子模块?

    我有一个非常旧的项目 其中直接包含另一个项目的源代码 而不是将其链接为库 回到糟糕的日子 当我将所有内容都保存在 CVS 中时 我将外部代码放在供应商分支上并定期导入 现在我的项目位于 git 中 将外部项目作为子模块包含进来会更有意义 但
  • 如何使用日期选择器在 Angular Material 5.0.0 中选择日期范围?

    我正在使用最新的Angular Material 5 0 0 rc0在我的 Angular 5 应用程序中 我正在尝试选择一个日期范围datepicker提供了 Angular 材料 但我找不到任何相关文档 我所能做的就是选择一个start
  • 最大化 div 的高度,周围元素的高度可变

    我有一个 div 我想在基于 100vh 的父级中最大化其大小 问题是我有两个pdiv 还可以根据窗口的宽度更改其高度 从而导致大小变化 现在 快速但肮脏的解决方案可能只是运行 jQuery 片段来检测父级的大小div and pdiv 并
  • 生成具有 2 个 OU 名称的 CSR

    我必须创建一个生成 CSR 的应用程序 在生成 CSR 时 我们需要填写一些详细信息 例如 CN OU 等 问题是我必须向其发送 CSR 的认证机构需要 2 个 OU 组织单位 名称 我用 google 搜索了很多 但找不到任何使用 ope
  • 如何在 Google Analytics 中跟踪“打开新标签”流量

    我有一个推荐网站 它使用一个网址来访问我的实施了谷歌分析的网站 当用户单击链接时 推荐网站会在同一窗口的新选项卡中打开我的网站 我想为每个推荐网站创建一个配置文件 以便每个配置文件都有自己的有关用户活动和交易转化的报告 我是谷歌分析的新手
  • R - 将 data.frame 转换为多维矩阵

    来自 data frame 的示例 x data frame c 1 1 2 2 3 3 c 1 2 1 2 1 2 c 1 1 1 2 2 2 c 12 14 22 24 34 28 colnames x c Store Dept Yea
  • 将 Google Analytics 添加到 Rails 4.2 应用程序

    我有一个使用 Heroku 部署的 Rails 4 2 应用程序 并且尝试向其中添加 Google Analytics 但是 Google Analytics 没有获取任何会话 有什么建议为什么以及如何解决这个问题吗 CODE app la
  • 在办公室 LAN 上设置 xampp 服务器

    我希望在小型办公室内使用 xampp 设置服务器 我当然会保护 xampp 但为了使我的 web 应用程序可供网络上的其他 4 台电脑使用 我是否只创建一个虚拟主机 有没有办法确保只能在局域网上访问Web应用程序 当前设置包括 4 台计算机
  • OpenGL 旋转

    我正在尝试在 OpenGL 中进行简单的旋转 但一定没有抓住重点 我并不是在寻找具体的修复方法 而是在寻找快速解释或更普遍地解释 OpenGL 旋转的链接 目前我有这样的代码 glPushMatrix glRotatef 90 0 0 0
  • 使用 Hadoop MapRed 排序

    Well 我想知道如何在reduce 任务之后更改简单WordCount 程序的排序顺序 我已经制作了另一个按值排序而不是按键排序的映射 但它仍然按升序排序 有没有一种简单的方法可以做到这一点 更改排序顺序 谢谢 韦洛佐 如果您使用的是旧版
  • Android Work Manager - Work Manager 是否能 100% 确保后台执行完成?

    根据我从文档中读到的内容https developer android com topic libraries architecture workmanager https developer android com topic libra
  • 如何限制pyqt中QLineEdit中的用户输入

    我有一个QLineEdit我想限制QLineEdit仅接受整数 它应该像输入掩码一样工作 但我不想用inputmask 因为如果用户点击QLineEdit光标将位于鼠标单击的位置 用户需要导航到 0 位置并输入他想要的内容 有没有什么替代方
  • 如何在 SQL Server 2012 中设置每周自动备份?

    请建议我如何在 SQL Server 2012 中设置自动数据库备份 我需要对 SQL Server 中的所有数据库 目前仅包含 3 个 进行每周自动备份 该备份在每周五 0100 点 凌晨 1 点 运行 这些备份文件 bak 应放置在 E
  • Swift NSScriptCommand 执行默认实现

    我在 Objective C 中使用了这段代码 implementation KDOrderInfo id performDefaultImplementation NSString theRequest self directParame
  • 使用 MailKit 和 Gmail OAuth 发送邮件

    我正在尝试创建一个应用程序 在客户购买时向他们发送电子邮件 我们有自己的 GMail 帐户 我将用它来发送电子邮件 我已经设置了我的应用程序并在 Google API 控制台中创建了凭据 我发现这个问题 https github com j
  • 如何调用API(Oauth 1.0)?

    我试图调用这个API Oauth1 0标准 https appcenter intuit com api v1 Connection Reconnect https appcenter intuit com api v1 Connectio
  • C/C++宏嵌套替换逻辑

    我正在尝试实现 C C 兼容的宏处理 我可以正确处理许多极端情况 包括此处讨论的情况 了解宏间接扩展自身时 C 预处理器的行为 https stackoverflow com questions 66593868 understanding