使用父宏的右括号的 C 预处理器

2023-12-24

我有这个有效的代码:

#include <stdio.h>
#define A(x) x B
#define B(x) C(x,
#define C(x,y) y x)
int main( void ) {
    printf( A("1") ("2") "3" );
}

它打印132(重点是A宏是将括号中参数后面的内容与后面的所有内容交换,直到另一个右括号)

但如果我在另一个宏中使用它:

#define Z(x) x
printf( Z( A("1") ("2") "3" ) );

我收到编译错误“未终止的类似函数的宏调用”。

我意识到发生这种情况是因为编译器正在尝试处理Z独立,但我需要使用它的右括号作为标记。有什么方法可以在宏中实现此功能吗?改变调用语法并不是一个真正的选择。


附注在我收到任何关于这是多么可怕的事情的回应之前,请放心:这不是针对真正的代码。这是在制作使用的玩具程序时出现的问题define在 C 中模拟一种新语言。


查看发生情况的最简单方法是稍微更改测试用例。

#define A(x) x B
#define B(x) C(x,
#define C(x,y) y x]  /* note close square bracket instead of close paren */

Y(A(1)(2)3)

预处理到Y(1 3 2]。这是因为扩张的中间阶段看起来像

Y(1 C(2,3)

此时C是近亲似乎属于Y原文中并将其替换为右括号。

现在,如果A(1)(2)3是在宏参数里面吗?

#define Z(x) x
Z(A(1)(2)3)

因为参数预扫描 http://gcc.gnu.org/onlinedocs/gcc-4.8.0/cpp/Argument-Prescan.html#Argument-Prescan,类似的扩张中间阶段是not

Z(1 C(2,3)

反而

1 C(2,3

with Z隐藏在隐藏的“待扩展”堆栈中。预处理器实际上是执行最后一个闭括号所属的文本外观Z, and C是不允许借用的。

我能想到的实现最初目标的侵入性最小的方法是

#define _A(x) x B
#define B(x) C(x,
#define C(x,y) y x)

#define Z(x) ZZ((_##x))
#define ZZ(x) ZZZ x
#define ZZZ(x) [x]

Z(A(1)(2)3)

预处理到[1 3 2]。我们使用令牌粘贴运算符来防止Z的参数被预扫描,所以我们可以添加一组临时的额外括号供使用C. ZZ and ZZZ然后再次将它们脱掉。问题是如果不粘贴就会出错x with 某物,所以我们必须在定义中添加一个前导下划线A,如果第一个标记为Z的参数永远不能在下划线之后进行标记粘贴。

您可能需要考虑使用M4 https://www.gnu.org/software/m4/而不是试图将其硬塞到 C 预处理器中。

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

使用父宏的右括号的 C 预处理器 的相关文章

  • SL4 AutoCompleteBox 重复筛选结果问题

    我在 AutoCompleteBox 过滤方面遇到问题 它似乎记住了之前的过滤器 例如 我输入 A 它会返回 1 项 我删除 A 并输入 Z 这应该返回 1 项 问题是它返回 A 过滤器加上 Z 的结果 我删除 Z 并输入 S 这会带回 2
  • SetWindowsHookEx 函数返回 NULL

    我正在研究 DLL 注入 但收到错误如下 挂接进程失败 87 参数不正确 目标进程和dll都是64位的 注入代码为 BOOL HookInjection TCHAR target TCHAR dll name https msdn micr
  • 为什么opencv videowriter这么慢?

    你好 stackoverflow 社区 我有一个棘手的问题 我需要你的帮助来了解这里发生了什么 我的程序从视频采集卡 Blackmagic 捕获帧 到目前为止 它工作得很好 同时我用 opencv cv imshow 显示捕获的图像 它也工
  • 使用不带参数的 Split() 时,默认分隔符是什么?

    所以我看了看String Split 今天 C 中的方法 我意识到你也可以向它传递零参数 这是我从未考虑过的 使用时默认的分隔符是什么Split 没有任何参数 如果没有值 则为空白 来源自here https msdn microsoft
  • 为什么派生类不使用基类的operator=(赋值运算符)?

    以下是实际问题的简化版本 而不是打电话Base operator int 代码似乎生成了一个临时的Derived对象并复制它 既然函数签名似乎完美匹配 为什么不使用基本赋值运算符 这个简化的示例没有显示任何不良影响 但原始代码在析构函数中有
  • 返回 int& 的函数[重复]

    这个问题在这里已经有答案了 我在网上查了一下发现一篇试图解释的文章std move和右值 http thbecker net articles rvalue references section 01 html并发现了一些我实在无法掌握的东
  • 如何使用汇编获取BIOS时间?

    我正在从头开始实现一个小型操作系统 用于教育目的 现在 我想使用汇编来获取 BIOS 时间 我对此进行了很多搜索 但找不到任何代码示例来执行此操作 如果有人可以提供任何参考或代码示例或与此相关的任何内容 我将非常感激 See 时钟中断 1a
  • 为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据?

    在流套接字上发送数据的标准方法始终是调用 send 并写入一大块数据 检查返回值以查看是否发送了所有数据 然后再次调用 send 直到整个消息被接受 例如 这是一个常见方案的简单示例 int send all int sock unsign
  • F10键没被抓住

    I have a Windows Form and there overriden ProcessCmdKey However this works with all of the F Keys except for F10 I am tr
  • Microsoft.Graph - 如何从具有不同用户名的共享邮箱发送?

    我目前正在将使用 SMTP 的服务代码移植到 Office 365 通过 SMTP 我可以使用 发件人 字段在来自共享收件箱的邮件上设置不同的用户名 同时保留共享电子邮箱地址 这似乎无法通过 Office 365 运行 其工艺流程为 客户填
  • QThread - 使用槽 quit() 退出线程

    我想在线程完成运行时通知对象 但是 我无法让线程正确退出 我有以下代码 处理器 cpp thread new QThread tw new ThreadWorker connect tw SIGNAL updateStatus QStrin
  • 如何不在类中实现接口的功能?

    面试时面试官问了我以下问题 但我不知道这个问题的答案是什么 请帮忙 如果我不想 我必须做什么 在我的类中实现一个函数 在接口中声明为 由我班实施 Edited 我正在使用 NET 和 C 如果有人可以提供 C 示例代码示例 那就太好了 Th
  • `cosf`、`sinf` 等不在 `std` 中 [重复]

    这个问题在这里已经有答案了 根据这里的讨论 我有报告了一个错误 https bugs launchpad net ubuntu source gcc 8 bug 1831385给 Ubuntu 开发者 编译以下示例 C 程序时 includ
  • 有没有更好的方法来获取每个项目与谓词匹配的子序列?

    假设我有一个 IEnumerable 例如 2 1 42 0 9 6 5 3 8 我需要获得与谓词匹配的项目的 运行 例如 如果我的谓词是 bool isSmallerThanSix int number 我想得到以下输出 2 1 0 5
  • 你能解释一下这个C++删除问题吗?

    我有以下代码 std string F WideString ws GetMyWideString std string ret StringUtils ConvertWideStringToUTF8 ws ret return ret W
  • 为什么C语言中可以使用多个分号?

    在 C 中我可以执行以下操作 int main printf HELLO WORLD 它有效 这是为什么 我个人的想法 分号是一个 NO OPERATION 来自维基百科 指示符 拥有一大串分号与拥有一个分号并告诉 C 语句已结束具有相同的
  • 将一个 long 转换为两个 int 以进行重构

    我需要将一个参数作为两个 int 参数传递给 Telerik Report 因为它不能接受长参数 将 long 拆分为两个 int 并在不丢失数据的情况下重建它的最简单方法是什么 使用掩蔽和移位是最好的选择 根据文档 long 保证为 64
  • 为什么 C# 接口名称前面加上“I”

    这种命名约定背后的基本原理是什么 我没有看到任何好处 额外的前缀只会污染 API 我的想法与康拉德一致response https stackoverflow com a 222502 9898与此相关的question https sta
  • 在何处将 CFLAG(例如 -std=gnu99)添加到 (Eclipse CDT) 自动工具项目中

    我有一个简单的 Autotools C 项目 不是 C 其框架是由 Eclipse CDT Juno 为我创建的 CFLAG 通过检查 似乎是 g O2 我希望所有生成的 make 文件也具有 std gnu99附加到 CFLAG 因为我使
  • 通过 cmake 链接作为外部项目包含的 opencv 库[重复]

    这个问题在这里已经有答案了 我对 cmake 比较陌生 经过几天的努力无法弄清楚以下事情 我有一个依赖于 opencv 的项目 它本身就是一个 cmake 项目 我想静态链接 opencv 库 我正在做的是我的项目中有一份 opencv 源

随机推荐