1. 基本用法

VA_ARGS 是 C/C++ 中的预定义宏,用于在宏定义中表示可变参数列表(Variadic Arguments),需与省略号 ... 配合使用。其核心作用是将宏调用中的可变参数原样传递给展开后的代码。

#define LOG(format, ...) printf(format, __VA_ARGS__)
LOG("Value: %d", 42); // 展开为 printf("Value: %d", 42)

注意: VA_ARGS 无法直接访问可变参数列表内的单个参数,也无法直接知道传递了多少个参数。

2. ##的使用

VA_ARGS 为空时,上面的用法会出现错误,因为format的后面多了一个逗号。为了避免语法错误需要使用 ## 告诉编译器,当可变参数为空时自动去掉前面的逗号。

#define LOG(format, ...) printf(format, ##__VA_ARGS__)
LOG("Value: %d", 42); // 展开为 printf("Value: %d", 42)
LOG("some message"); // 展开为 printf("some message")

3. 获取可变参数的个数

常见的方式如下,parameterNum()得出了输入的参数数目。

#define get5th(a1, a2, a3, a4, a5, ...) a5
// ... getnth(a1, a2, a3, ... , an, ...) an
#define parameterNum(...) get5th(__VA_ARGS__, 4, 3, 2, 1) parameterNum(a)
//get5th(a, 4, 3, 2, 1)
//1 parameterNum(a, b, c)
//get5th(a, b, c, 4, 3, 2, 1)
//3

但是当__VA_ARGS__参数数目为0时会出现多余的逗号,计算结果还是1,需要进一步处理。

#define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, N, ...) N
#define COUNT_ARGS(...) __COUNT_ARGS(, ##__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) COUNT_ARGS(a)
//__COUNT_ARGS(a, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
//1 COUNT_ARGS()
//__COUNT_ARGS(, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
//0

4. QT 预置的宏

QT 在文件 qoverload.h 中提供了对可变参数的宏,单可变参数数量小于10个时可以直接使用QT提供的宏 QT_OVERLOADED_MACRO(MACRO, ...)。

#define QT_VA_ARGS_CHOOSE(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N
#define QT_VA_ARGS_EXPAND(...) __VA_ARGS__ // Needed for MSVC
#define QT_VA_ARGS_COUNT(...) QT_VA_ARGS_EXPAND(QT_VA_ARGS_CHOOSE(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define QT_OVERLOADED_MACRO_EXPAND(MACRO, ARGC) MACRO##_##ARGC
#define QT_OVERLOADED_MACRO_IMP(MACRO, ARGC) QT_OVERLOADED_MACRO_EXPAND(MACRO, ARGC)
#define QT_OVERLOADED_MACRO(MACRO, ...) QT_VA_ARGS_EXPAND(QT_OVERLOADED_MACRO_IMP(MACRO, QT_VA_ARGS_COUNT(__VA_ARGS__))(__VA_ARGS__))

用法示例:

#define sum_1(num1) num1
#define sum_2(num1, num2) num1 + num2
#define sum_3(num1, num2, num3) num1 + num2 + num3
#define sum_4(num1, num2, num3, num4) num1 + num2 + num3 + num4
#define sum_5(num1, num2, num3, num4, num5) num1 + num2 + num3 + num4 + num5 #define sum(...) QT_OVERLOADED_MACRO(sum, __VA_ARGS__) int x = sum(1,2);
//int x = 1+2;
QString s = sum("a", "b");
// QString s = "a" +"b";

参考:

C语言可变参数宏定义方法

【Just For Fun】C - 宏开发 - 选取第 n 项参数、按照参数数目展开不同的宏、缺陷

【宏定义】——获取可变参数宏的参数数量

C++宏定义中可变参数列表__VA_ARGS__ 及 QT 提供的宏 QT_OVERLOADED_MACRO的更多相关文章

  1. C语言 宏定义之可变参数

    可变参数宏定义 C99编译器标准允许你可以定义可变参数宏(variadic macros),这样你就可以使用拥有可以变化的参数表的宏.可变参数宏就像下面这个样子: #define dbgprint(. ...

  2. GNU中宏定义对可变参数的支持(引自百度)

    http://zhidao.baidu.com/question/125413478.html 问:#define PDEBUG(fmt,args...) fprintf(stderr,fmt, ## ...

  3. C语言函数可变参数列表

    C语言允许使用可变参数列表,我们常用的printf函数即为可变参数函数,C标准库提供了stdarg.h为我们提供了这方面支持:该头文件提供了一些类型和宏来支持可变参数列表,包括类型va_list,宏v ...

  4. C++可变参数列表处理宏va_list、va_start、va_end的使用

      VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef     _M_ALPHA typedef    struct{ char* a0; /* ...

  5. 【转】C++可变参数列表处理宏va_list、va_start、va_end的使用

    VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef     _M_ALPHA typedef    struct{ char* a0; /*po ...

  6. 可变参数列表---以dbg()为例

    在UART驱动的drivers/serial/samsung.h中遇到如下定义: #ifdef CONFIG_SERIAL_SAMSUNG_DEBUG extern void printascii(c ...

  7. C语言中可变参数的原理——printf()函数

    函数原型: int printf(const char *format[,argument]...) 返 回 值: 成功则返回实际输出的字符数,失败返回-1. 函数说明: 使用过C语言的人所再熟悉不过 ...

  8. define宏定义中的#,##,@#及\符号

    define宏定义中的#,##,@#及\符号 在#define中,标准只定义了#和##两种操作.#用来把参数转换成字符串,##则用来连接两个前后两个参数,把它们变成一个字符串. 1.# (string ...

  9. C语言可变参数在宏定义中的应用

    在C语言的标准库中,printf.scanf.sscanf.sprintf.sscanf这些标准库的输入输出函数,参数都是可变的.在调试程序时,我们可能希望定义一个参数可变的输出函数来记录日志,那么用 ...

  10. Python学习笔记之7.5 - 定义有默认参数的函数》》》直接在函数定义中给参数指定一个默认值,默认参数的值应该是不可变的对象

    问题: 你想定义一个函数或者方法,它的一个或多个参数是可选的并且有一个默认值. 解决方案: 定义一个有可选参数的函数是非常简单的,直接在函数定义中给参数指定一个默认值,并放到参数列表最后就行了.例如: ...

随机推荐

  1. SpringBoot 项目模板-摆脱步步搭建

    本文以一个简单的电商订单系统为例,源代码请访问: git clone https://github.com/e-commerce-sample/order-backendgit checkout a4 ...

  2. Collection接口与其子接口实现类-----总复习

    数组与集合 1. 集合与数组存储数据概述:集合.数组都是对多个数据进行存储操作的结构,简称Java容器.说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi, ...

  3. 腾讯云 TI 平台部署与调用DeepSeek-R1大模型的实战指南

    今天我们将继续探讨如何部署一个私有化的 DeepSeek-R1 大模型,具体的部署过程我们将利用腾讯云的 TI 平台进行操作.当前,腾讯云 TI 平台为用户提供了免费体验的满血版 DeepSeek-R ...

  4. 玩转云端|天翼云边缘安全加速平台AccessOne实用窍门之让办公访问安全、高效又稳定

    本文分享自天翼云开发者社区<玩转云端|天翼云边缘安全加速平台AccessOne实用窍门之让办公访问安全.高效又稳定>,作者:天翼云社区官方账号 随着社会信息化程度不断提高,远程办公已经成为 ...

  5. 天翼云GPU云主机:共享信息技术与虚拟机的完美融合

    本文分享自天翼云开发者社区<天翼云GPU云主机:共享信息技术与虚拟机的完美融合>,作者:不知不觉 在云计算领域,GPU云主机已经成为了一个备受瞩目的焦点.它的出现改变了传统IT架构的方式, ...

  6. 同步工具-Oceanus打通mysql到Iceberg

    一.服务配置 已配置好gt_oneline_2,其它集群还需按照下面方式特殊配置 1.需要腾讯Oceanus同学在后端修改高途flink集群配置core-site.xml文件,增加如下配置.只能绑定一 ...

  7. 揭秘 Sdcb Chats 如何解析 DeepSeek-R1 思维链

    在上一篇文章中,我介绍了 Sdcb Chats 如何集成 DeepSeek-R1 模型,并利用其思维链(Chain of Thought, CoT)功能增强 AI 推理的透明度.DeepSeek-R1 ...

  8. macbookpro m3本地部署DeepSeek模型

    macbookpro m3有着十分强大的性能.在deepseek如火如荼的当下,可以尝试在本地部署并使用.还可以将自己的文档作为语料喂给deepseek,使其能成为自己专属的AI助手. 本文介绍使用o ...

  9. Typecho博客网站底部添加网站已运行时间教程

    样式一: 1. 将代码放入 functions.php 一般在主题根目录:网站 /usr/themes/ 主题 修改一下你自己的网站时间 // 设置时区 date_default_timezone_s ...

  10. 启动Eclipse时报错如何解决?

    启动Eclipse出现弹框,弹框报错内容如下: A Java Runtime Enviroment(JRE)or Java Development Kit(JDK) must be available ...