如何在函数定义和函数调用中使用可变宏参数?

2023-12-12

我正在尝试使用宏根据宏的参数定义几个类似的函数。然而,结果函数需要采用的参数的数量和类型在所有函数中并不相同,但我还需要将函数的所有参数传递到函数体内的另一个可变参数函数中。

我想要完成的事情的一个最小例子:

#define COMMAND(__COMMAND__, __FORMAT__, ...) \
  void __COMMAND__ ( __VA_ARGS__ ) {          \
    printf( __FORMAT__, ##__VA_ARGS__ );      \
  }

COMMAND( Start,        "m start %c\r", (char) unit )
COMMAND( Home,         "m home\r" )
COMMAND( Add_To_Chart, "cv 0 %d %d\r", (int) ch1, (int) ch2 )
// literally hundreds of additional COMMANDs needed here.

(请注意,该函数的实际逻辑要复杂得多。)

但是,我无法找出既作为函数定义中的参数列表又作为函数调用中的参数列表有效的语法。

使用表格(type)arg不是函数定义的有效语法,但我可以将其传递给printf很好(它被视为演员)。

COMMAND( A, "cv 0 %d %d\r", (int)ch1, (int)ch2 )
// error: expected declaration specifiers or ‘...’ before ‘(’ token
// void A ( (int)ch1, (int)ch2 ) {
//   printf( "cv 0 %d %d\r", (int)ch1, (int)ch2 );
// }

换个方式做,type(arg),似乎适用于函数声明,但函数样式强制转换仅在 C++ 中可用,在 C 中不可用,因此它失败printf.

COMMAND( B, "cv 0 %d %d\r", int(ch1), int(ch2) )
// error: expected expression before ‘int’
// void B ( int(ch1), int(ch2) ) {
//   printf( "cv 0 %d %d\r", int(ch1), int(ch2) );
// }

如何使用可变参数宏参数作为函数的参数定义和传递给另一个函数的参数?


不要做__*代码中的标识符。__COMMAND__ and __FORMAT__使您的代码无效。

您必须让预处理器了解类型。将它们作为单独的令牌传递,然后将它们打乱,例如在因参数数量而超载的单独链中。

// Create function arguments
#define ARGS_0()            void
#define ARGS_2(t1,v1)        t1 v1
#define ARGS_4(t1,v1,t2,v2)  t1 v1, t2 v2
#define ARGS_N(_4,_3,_2,_1,_0,N,...)   ARGS##N
#define ARGS(...)   ARGS_N(_0,##__VA_ARGS__,_4,_3,_2,_1,_0)(__VA_ARGS__)

// Pass arguments to printf with a leading comma.
#define PASS_0()
#define PASS_2(t1,v1)       , v1        
#define PASS_4(t1,v1,t2,v2) , v1, v2
#define PASS_N(_4,_3,_2,_1,_0,N,...)  PASS##N
#define PASS(...)  PASS_N(_0,##__VA_ARGS__,_4,_3,_2,_1,_0)(__VA_ARGS__)

#define COMMAND(cmd, fmt, ...) \
  void cmd(ARGS(__VA_ARGS__)) { \
    printf(fmt PASS(__VA_ARGS__)); \
  }

COMMAND( Start,        "m start %c\r", char, unit)
COMMAND( Home,         "m home\r")
COMMAND( Add_To_Chart, "cv 0 %d %d\r", int, ch1, int, ch2)

扩展到:

void Start(char unit) { printf("m start %c\r" , unit); }
void Home(void) { printf("m home\r" ); }
void Add_To_Chart(int ch1, int ch2) { printf("cv 0 %d %d\r" , ch1, ch2); }

您可以通过在参数数量上重载单个“对每对参数应用一个宏并将它们与此连接,如果为空则使用此”宏来使代码更加通用。

#define ESC(...)  __VA_ARGS__

#define APPLYTWOJOIN_0(f,j,e)            ESC e
#define APPLYTWOJOIN_2(f,j,e,t,v)      f(t,v)
#define APPLYTWOJOIN_4(f,j,e,t,v,...)  f(t,v) ESC j \
        APPLYTWOJOIN_2(f,j,e,__VA_ARGS__)
#define APPLYTWOJOIN_6(f,j,e,t,v,...)  f(t,v) ESC j \
        APPLYTWOJOIN_4(f,j,e,__VA_ARGS__)
#define APPLYTWOJOIN_8(f,j,e,t,v,...)  f(t,v) ESC j \
        APPLYTWOJOIN_6(f,j,e,__VA_ARGS__)
// etc.
#define APPLYTWOJOIN_N(_8,_7,_6,_5,_4,_3,_2,_1,_0,N,...)  \
        APPLYTWOJOIN##N
// For every two arguments in the list, apply function `f(a,b)` on it.
// Join every result of that function with `ESC j`.
// Expand empty result to `ESC e`.
#define APPLYTWOJOIN(f, j, e, ...)  \
        APPLYTWOJOIN_N(_0,##__VA_ARGS__,_8,_7,_6,_5,_4,_3,_2,_1,_0)\
        (f,j,e,##__VA_ARGS__)

// Pass argument to printf. The leading comma is after format string.
#define PASS(t,v)  , v
// Pass arguments in function parameter list.
#define ARGS(t,v)  t v

#define COMMAND(cmd, fmt, ...) \
  void cmd( APPLYTWOJOIN(ARGS, (,), (void), ##__VA_ARGS__) ) { \
    printf(fmt APPLYTWOJOIN(PASS, (), (), ##__VA_ARGS__) ); \
  }

COMMAND( Start,        "m start %c\r", char, unit)
COMMAND( Home,         "m home\r")
COMMAND( Add_To_Chart, "cv 0 %d %d\r", int, ch1, int, ch2)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在函数定义和函数调用中使用可变宏参数? 的相关文章

  • 使用 std::packaged_task/std::exception_ptr 时,线程清理程序报告数据争用

    我遇到了线程清理程序 TSan 的一些问题 抱怨某些生产代码中的数据争用 其中 std packaged task 通过将它们包装在 std function 中而移交给调度程序线程 对于这个问题 我简化了它在生产中的作用 同时触发 TSa
  • 如何在 .NET Framework 2.0 中模拟“Func<(Of <(TResult>)>) 委托”?

    我尝试使用这个类代码项目文章 http www codeproject com KB threads AsyncVar aspx在 VB NET 和 NET Framework 2 0 中 除了这一行之外 所有内容似乎都可以编译Privat
  • Directory.Delete 之后 Directory.Exists 有时返回 true ?

    我有非常奇怪的行为 我有 Directory Delete tempFolder true if Directory Exists tempFolder 有时 Directory Exists 返回 true 为什么 可能是资源管理器打开了
  • 如何将 protobuf-net 与不可变值类型一起使用?

    假设我有一个像这样的不可变值类型 Serializable DataContract public struct MyValueType ISerializable private readonly int x private readon
  • 错误:表达式不产生值

    我尝试将以下 C 代码转换为 VB NET 但在编译代码时出现 表达式不产生值 错误 C Code return Fluently Configure Mappings m gt m FluentMappings AddFromAssemb
  • 使用 Newtonsoft 和 C# 反序列化嵌套 JSON

    我正在尝试解析来自 Rest API 的 Json 响应 我可以获得很好的响应并创建了一些类模型 我正在使用 Newtonsoft 的 Json Net 我的响应中不断收到空值 并且不确定我的模型设置是否正确或缺少某些内容 例如 我想要获取
  • 由 IHttpClientFactory 注入时模拟 HttpClient 处理程序

    我创建了一个自定义库 它会自动为依赖于特定服务的 Polly 策略设置HttpClient 这是使用以下方法完成的IServiceCollection扩展方法和类型化客户端方法 一个简化的例子 public static IHttpClie
  • 在 C 中初始化变量

    我知道有时如果你不初始化int 如果打印整数 您将得到一个随机数 但将所有内容初始化为零似乎有点愚蠢 我问这个问题是因为我正在评论我的 C 项目 而且我对缩进非常直接 并且它可以完全编译 90 90 谢谢 Stackoverflow 但我想
  • Qt - ubuntu中的串口名称

    我在 Ubuntu 上查找串行端口名称时遇到问题 如您所知 为了在 Windows 上读取串口 我们可以使用以下代码 serial gt setPortName com3 但是当我在 Ubuntu 上编译这段代码时 我无法使用这段代码 se
  • 为什么 std::strstream 被弃用?

    我最近发现std strstream已被弃用 取而代之的是std stringstream 我已经有一段时间没有使用它了 但它做了我当时需要做的事情 所以很惊讶听到它的弃用 我的问题是为什么做出这个决定 有什么好处std stringstr
  • 外键与独立关系 - Entity Framework 5 有改进吗?

    我读过了several http www ladislavmrnka com 2011 05 foreign key vs independent associations in ef 4 文章和问题 https stackoverflow
  • 使用管道时,如果子进程数量大于处理器数量,进程是否会被阻塞?

    当子进程数量很大时 我的程序停止运行 我不知道问题是什么 但我猜子进程在运行时以某种方式被阻止 下面是该程序的主要工作流程 void function int process num int i initial variables for
  • 按 Esc 按键关闭 Ajax Modal 弹出窗口

    我已经使用 Ajax 显示了一个面板弹出窗口 我要做的是当用户按 Esc 键时关闭该窗口 这可能吗 如果有人知道这一点或以前做过这一点 请帮助我 Thanks 通过以下链接 您可以通过按退出按钮轻松关闭窗口 http www codepro
  • 如果没有抽象成员,基类是否应该标记为抽象?

    如果一个类没有抽象成员 可以将其标记为抽象吗 即使没有实际理由直接实例化它 除了单元测试 是的 将不应该实例化的基类显式标记为抽象是合理且有益的 即使在没有抽象方法的情况下也是如此 它强制执行通用准则来使非叶类抽象 它阻止其他程序员创建该类
  • 如何部署“SQL Server Express + EF”应用程序

    这是我第一次部署使用 SQL Server Express 数据库的应用程序 我首先使用实体 框架模型来联系数据库 我使用 Install Shield 创建了一个安装向导来安装应用程序 这些是我在目标计算机中安装应用程序所执行的步骤 安装
  • System.IO.FileNotFoundException:找不到网络路径。在 Windows 7 上使用 DirectoryEntry 对象时出现异常

    我正在尝试使用 DirectoryEntry 对象连接到远程 Windows 7 计算机 这是我的代码 DirectoryEntry obDirEntry new DirectoryEntry WinNT hostName hostName
  • 无法接收 UDP Windows RT

    我正在为 Windows 8 RT 编写一个 Windows Store Metro Modern RT 应用程序 需要在端口 49030 上接收 UDP 数据包 但我似乎无法接收任何数据包 我已按照使用教程进行操作DatagramSock
  • WebSocket安全连接自签名证书

    目标是一个与用户电脑上安装的 C 应用程序交换信息的 Web 应用程序 客户端应用程序是 websocket 服务器 浏览器是 websocket 客户端 最后 用户浏览器中的 websocket 客户端通过 Angular 持久创建 并且
  • Oracle Data Provider for .NET 不支持 Oracle 19.0.48.0.0

    我们刚刚升级到 Oracle 19c 19 3 0 所有应用程序都停止工作并出现以下错误消息 Oracle Data Provider for NET 不支持 Oracle 19 0 48 0 0 我将 Oracle ManagedData
  • 从列表中选择项目以求和

    我有一个包含数值的项目列表 我需要使用这些项目求和 我需要你的帮助来构建这样的算法 下面是一个用 C 编写的示例 描述了我的问题 int sum 21 List

随机推荐

  • Python Plotly 图表更新有两个下拉菜单

    我正在尝试在 Jupyter Lab 中构建一个绘图散点图 以便能够查看 DataFrame 中各个列之间的依赖关系 我想要两个下拉菜单 对应于 X 轴和 Y 轴 每个菜单中都有 DF 列的完整列表 当我在任何菜单中选择一列时 相应轴上的数
  • iOS 基本 FTP 设置;读写流

    我正在尝试创建一个具有一些非常基本的 FTP 功能的 iOS 5 应用程序 并且需要一些指导 它将连接到本地网络上的设备并使用 dat txt 文件执行读 写操作 在过去的几天里 我进行了一些搜索 并看到了各种建议 但没有什么足够简单 我可
  • 如何实现“回收站”功能?

    我正在开发一个 Java 桌面应用程序 需要在其中实现回收站功能 现在 我使用桌面应用程序将文件复制到名为回收站的文件夹中 然后删除原始文件 我将目标路径存储在一个文本文件中 其中文件被删除 只是为了将文件恢复到原始位置 恢复文件时 我只是
  • 如何使用 mysql 创建每周队列分析表?

    假设您有一个用户表 其中至少包含用户注册的日期和 ID 现在 假设您有一个单独的表 用于跟踪可能在用户生命周期中的任何时刻发生的操作 例如付款 比如应用内购买 在该表中 我们跟踪用户 ID 付款日期和付款 ID 所以我们有类似这样的东西来设
  • 使用地理编码初始化 React Google Maps StandaloneSearchBox

    有人可以告诉我如何使用类型初始化React Google Maps的StandaloneSearchBox组件 geocode 就像原始的google maps places Autocomplete一样 这样我就可以限制自动完成的输入建议
  • 使用 Json.Net 在 C# 中解析 Json

    Posts id 1 title Bibidh prothom khondo content sjih sdkljjdsf kdjsfjks author last update 23 june 2013 Comments id 1 con
  • 复选框 + Jquery 隐藏/显示

    我有一系列的行和复选框来过滤它们 ul li li ul
  • 表中可编辑字段之间的 Tab 键切换

    我正在使用这里的代码http www korvus com blog geek making the tab key work with jeditable fields 在 jeditable 字段之间进行制表符工作 如果这些字段是独立的
  • INSERT 语句与 FOREIGN KEY 约束“FK_PostTag_Tag_TagId”冲突

    我在用实体框架 7 RC1我有实体 public class Post public Int32 Id get set public String Title get set public virtual IList
  • 最后进入异常处理

    到底是什么作用finally阻止异常处理执行 它保存应该始终执行的代码 无论是否发生异常 例如 如果您打开了一个文件 则应该在finally阻止以确保它始终处于关闭状态 如果您将其关闭try块 较早的异常将导致执行直接跳转到catch阻止并
  • Shunting-Yard VS 递归下降解析器

    我正在构建一个高级数学解析器 并且想知道 Shunting Yard 和其他可用解析器算法 例如 Descent Parser 之间的区别 因为我更喜欢以 RPN 表示法存储公式 提前致谢 我从来没有太多使用 调车场 算法 因为它似乎只关注
  • 如何为从 NIB 加载的 NSWindow 提供焦点?

    我在用着NSWindowController从 NIB 加载窗口 然而 当我打电话时showWindow 该窗口在视觉上位于最上面 但焦点仍保持在原来的位置 而不是将其移动到新窗口 It s easy to see this happeni
  • java中的日历日期为yyyy-MM-dd格式

    如何将日历日期转换为yyyy MM dd format Calendar cal Calendar getInstance cal add Calendar DATE 1 Date date cal getTime SimpleDateFo
  • 为什么 pytesseract 不能识别单个数字?

    I am performing ocr on a site and specifically on these two images 我对 OCR 相当陌生 我使用以下内容 from PIL import Image import pyte
  • 如何使用 jQuery 增加数量字段的值?

    我有一个带有一些数量字段的表格 每一侧都有一个加号和减号
  • .NET 中的网络文件复制

    我有一个运行 Samba 共享的 Ubuntu 盒子 向所有人开放 我可以通过 ip 地址访问它 所以我知道我可以完全访问它 在我的应用程序中 我正在尝试以下操作 但它无法通过 IP 地址 仅 DNS 名称 工作 val ip addres
  • 有没有更好的方法来设置 JPanel 图形的初始位置?)

    在梁的第15章中Java 编程简介 第七版 他介绍了一个程序 可以在 JPanel 上制作一个 2 D 球 并通过单击放大 缩小按钮来放大它 我修改了程序 以便它还可以 1 在用户单击 选项 单击时放大 缩小球 2 允许您通过按下按钮来选择
  • 矩阵求逆的最快方法

    我想用反函数和很多函数处理图像 为了让代码快速运行 有谁能在 3 种反转方法中建议一种快速方法吗 double cvInvert const CvArr src CvArr dst int method CV LU CV LU 高斯消除并选
  • 如何将天数添加到字符串数据类型的 jtextfield 中给出的日期

    再会 我只是想问一下在给定日期中添加天数 我有一个 jtexfield txtStart 和另一个 jtexfield txtExpiry 我需要在 txtExpiry 中显示距 txtStart 中的日期 102 天后的日期 我正在使用
  • 如何在函数定义和函数调用中使用可变宏参数?

    我正在尝试使用宏根据宏的参数定义几个类似的函数 然而 结果函数需要采用的参数的数量和类型在所有函数中并不相同 但我还需要将函数的所有参数传递到函数体内的另一个可变参数函数中 我想要完成的事情的一个最小例子 define COMMAND CO