当前位置: 首页 > news >正文

【c语法】##__VA_ARGS__与__VA_ARGS__

欢迎来到 破晓的历程的 博客

⛺️不负时光,不负己✈️

文章目录

    • 引言
    • __VA_ARGS__

引言

在调试过程中,我们经常会自定义打印,比如日志信息的输出,这时就会用VA_ARGS,接下来详细讲解!

VA_ARGS

__VA_ARGS__是C语言设定的一个预定义宏,用于处理可变参数的参数列表。通常用在宏定义中,以便宏可以接收不定数量的参数,并将他们作为整体处理。
通常的函数参数列表都是固定的,但也存在着不定参数数量的函数,如:printf
,为了定义可以处理不同参数个数的宏,C99标准引入了 VA_ARGS,下列的代码均在C99及C99以上标准的环境下运行。

__VA_ARGS__表示所有在宏调用中传递的额外参数。它可以放在宏定义的参数列表的末尾,用于接收任意数量的额外参数,比如:

#define LOG_DEBUG(format,...) printf(format,__VA_ARGS__)

解析:

  • DEBUG_LOG 是一个宏,接受至少一个参数 fmt(格式化字符串),后面可以是任意数量的参数。
  • VA_ARGS 表示可变参数列表,在宏展开时会被替换为传递给 DEBUG_LOG 宏的所有实际参数。
    示例:
#define LOG_(format,...) printf("[%s:%d]"format"\n",__FILE__,__LINE__,__VA_ARGS__);

如上的代码就是对日志定义的一个宏。


##VA_ARGS

大家在了解__VA_ARGS__时,一定会看到有些地方在该宏定义前使用 ## 运算符来处理可变参数,如:

#define DEBUG_LOG(fmt, ...) \printf("[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)

##__VA_ARGS__前面加上##的作用是:当可变参数的个数为0时,这里的##可以把把前面多余的","去掉,否则会编译出错。
当想要在自定义的调试信息加上时间、行数等信息时,应该怎么做呢?先把正确的用法写在前面:

#include <stdio.h>#define LOG3(fmt, ...)          printf("<%s:%s>:"fmt"\r\n", __FILE__, __FUNCTION__, ##__VA_ARGS__)
int main(int argc, char** argv)
{char *str = "test __VA_ARGS__";int num = 10086;LOG3("this is test __VA_ARGS__");LOG3("this is test __VA_ARGS__:%s, %d", str, num);LOG3();return 0;
}

结果为:

<main.c:main>:this is test __VA_ARGS__
<main.c:main>:this is test __VA_ARGS__:test __VA_ARGS__, 10086
<main.c:main>:

但是如果不加##:可变参数为空时,报错。

#include <stdio.h>#define LOG2(fmt, ...)          printf("<%s:%s>:"fmt"\r\n", __FILE__, __FUNCTION__, __VA_ARGS__)
int main(int argc, char** argv)
{LOG2();//不传参数,编译报错LOG2("this is test __VA_ARGS__");//编译报错LOG2("this is test __VA_ARGS__:%s, %d", str, num);//正常编译return 0;
}

分析:

  • 第6行没有传参数,宏定义LOG2(fmt,…)展开后,__VA_ARGS__是空的,这时printf后面剩余一个,,必然编译失败;
  • 第7行虽然传入了字符串,但是该字符串赋值给了LOG2(fmt,…)的第一个参数fmt,宏展开后,printf后面也剩余一个,,所以编译报错。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 深度学习--负采样技术及其扩展详解
  • redisj集群之哨兵模式
  • LeetCode面试题Day16|LC56 合并区间、LC57 插入区间
  • 浅谈Java SpringBoot和Spring区别
  • 【Linux】05.Linux 下的编辑器——vim
  • C语言 | Leetcode C语言题解之第373题查找和最小的K对数字
  • 学懂C++(四十五 ):深入详解C++ STL 容器:从基础到进阶
  • 深度学习——分布式训练
  • Webpack中的 HTTP 压缩
  • c语言个人笔记
  • netty编程之实现HTTP服务
  • 采用java或者python获取视频流的方法
  • 【功能实现】axios实现动态数据
  • 【卡码网C++基础课 13.链表的基础操作1】
  • 婚恋交友系统该如何制作成品系统?
  • Asm.js的简单介绍
  • ES6之路之模块详解
  • Facebook AccountKit 接入的坑点
  • Java IO学习笔记一
  • php中curl和soap方式请求服务超时问题
  • 马上搞懂 GeoJSON
  • 再谈express与koa的对比
  • python最赚钱的4个方向,你最心动的是哪个?
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ‌JavaScript 数据类型转换
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #100天计划# 2013年9月29日
  • #Datawhale AI夏令营第4期#AIGC方向 文生图 Task2
  • $nextTick的使用场景介绍
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (floyd+补集) poj 3275
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (回溯) LeetCode 77. 组合
  • (七)Java对象在Hibernate持久化层的状态
  • (实测可用)(3)Git的使用——RT Thread Stdio添加的软件包,github与gitee冲突造成无法上传文件到gitee
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (转)jQuery 基础
  • (转)scrum常见工具列表
  • (转)VC++中ondraw在什么时候调用的
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .net(C#)中String.Format如何使用
  • .NET/C# 使用反射注册事件
  • .NET单元测试
  • .NET开源纪元:穿越封闭的迷雾,拥抱开放的星辰
  • .NET连接MongoDB数据库实例教程
  • .Net中的集合
  • /dev下添加设备节点的方法步骤(通过device_create)
  • @Autowired多个相同类型bean装配问题
  • @Valid和@NotNull字段校验使用
  • [240727] Qt Creator 14 发布 | AMD 推迟 Ryzen 9000芯片发布
  • [AI 大模型] 百度 文心一言
  • [BT]小迪安全2023学习笔记(第15天:PHP开发-登录验证)