C 语言 define 变参__VA_ARGS__使用
在C语言的标准库中,printf、scanf、sscanf、sprintf、sscanf这些标准库的输入输出函数,参数都是可变的。在调试程序时,我们可能希望定义一个参数可变的输出函数来记录日志,那么用可变参数的宏是一个不错的选择。
在C99中规定宏也可以像函数一样带可变的参数,如:
#define LOG(format, ...) fprintf(stdout, format, __VA_ARGS__)
其中,...表示可变参数列表,__VA_ARGS__在预处理中,会被实际的参数集(实参列表)所替换。
同时gcc还支持带可以变参数名的方式(注意:VC不支持):
#define LOG(format, args...) fprintf(stdout, format, args)
同样,args在预处理过程中,会被实际的参数集所替换。其用法和上面的方式一样,只是参数的符号有变。
需要注意的是,上述两种方式的可变参数不能省略,尽管可以传一个空参数进去。说到这里,有必要提一下“##”连接符号的用法,“##”的作用是对token进行连接,上例中format,args,__VA_ARGS都可以看作是token,如果token为空,“##”则不进行连接,所以允许省略可变参数。对上述2个示例的改造:
#define LOG(format, ...) fprintf(stdout, format, ##__VA_ARGS__)
#define LOG(format, args...) fprintf(stdout, format, ##args)
即然参数可以省略,那么用宏定义一个开关,实现一个输出日志的函数就简单了:
#ifdef DEBUG
#define LOG(format, ...) fprintf(stdout, ">>>>>" format "<<<<", ##__VA_ARGS__)
#else
#define LOG(format, ...)
#endif
example
#include "stdio.h"
#define LOG_TYPE1(format, ...) do{ \
printf(format, __VA_ARGS__); \
\
} while(0)
#define LOG_TYPE2(format, args...) do{ \
printf(format, args); \
\
} while(0)
#define LOG_TYPE3(format, ...) do{ \
printf(format, ##__VA_ARGS__); \
\
} while(0)
#define LOG_TYPE4(format, args...) do{ \
printf(format, ##args); \
\
} while(0)
#define LOG(x) printf("LOG "#x" %d \n", x);
int value = 10;
int main()
{
printf("hello world. \n");
//LOG_TYPE1("hello %d \n"); error
LOG_TYPE1("hello %d \n", 1);
//LOG_TYPE2("hello \n"); error
LOG_TYPE2("hello %d \n", 2);
LOG_TYPE3("hello 3\n");
LOG_TYPE3("hello %d\n", 3);
LOG_TYPE4("hello 4\n");
LOG_TYPE4("hello %d\n", 4);
LOG(10);
LOG(value);
return 0;
}
C 语言 define 变参__VA_ARGS__使用的更多相关文章
- C语言可变参实现参数累加返回
C语言可变参的作用真的是非常大,自从发表了可变参如何实现printf,fprintf,sprintf的文章以来,便有不少博友私信问我实现的机制,我也解释了相关的知识点.今天,我们借着这个机会,再来举一 ...
- c语言可变参
一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,…),int ...
- C语言-define 与do{}while(0)
问题引出: 我们都知道宏定义#define只是简单替换,所以遇到复杂的带参数宏,必须很小心的为需要的参数加上括号“()”:同样碰到复杂的多条语句替代,虽然加{}可以将其封装成一个整体,但同时又有另一个 ...
- c语言#define用法
01 作用域 预编译作用域限本文全局,如: a.c中定义:#define TEST 1 b.c中定义:#define TEST 2 两者编译不交叉,互不影响. 若需#define TEST作用于a.c ...
- C语言define 可以提高程序运行的速度
define的优缺点 优点 提高了程序的可读性,同时也方便进行修改: 提高程序的运行效率:使用带参的宏定义既可完成函数调用的功能,又能避免函数的出栈与入栈操作,减少系统开销,提高运行效率: 3.宏是由 ...
- c语言define和typedef区别和使用
define完全可以理解替换,typedef代表别名.听着差不多的意思,那2者区别在哪? 先来个简单例子查看基本使用. //define和typedef区别 #define DB double //替 ...
- C语言 define实现的宏函数汇总
最大值,最小值 #define MAX( x, y ) ( (x) > (y) ? (x) : (y) )#define MIN( x, y ) ( (x) < (y) ? (x) : ( ...
- C语言的变参列表 va_list
1. va_list的基本原理和用法 #include<stdio.h> #include<stdarg.h> void func(int i,char *ch,...){ / ...
- 【C语言】中的版本规范(C89 C99等)
C语言中的版本 一.相关基础知识 ISO:国际标准化组织(International Organization for Standardization,ISO)简称ISO,是一个全球性的非政府组织,是 ...
随机推荐
- NYOJ--513--A+B Problem IV(大数)
A+B Problem IV 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 acmj最近发现在使用计算器计算高精度的大数加法时很不方便,于是他想着能不能写个程序把这 ...
- 初笔,JAVA.HelloWorld代码详解
HelloWorld.java //文件名 public class HelloWorld{ public static void main(String[] args){ System.out.pr ...
- .net 设置webbrowser控件使用的IE版本
当我们在使用.net的Webbrowser控件时,发现webbrowser展示的内容和我们用浏览器展示的内容不一致,甚至出现:'JSON' is undefined. 原因是webbrowser使用的 ...
- Unity Editor 检查工程Prefab(预设)中的空组件
在我们做项目的过程中 经常会有预设中出现空的脚本 例如: 导致的原因是因为 脚本的丢失 现在我们来做一个检查工程中有空脚本的预设工具 老规矩直接上代码 放到工程就能用 using UnityEngin ...
- M3
一,使用媒体查询的三种方式 1.直接在CSS中使用: @media 类型:(长选用all/screen)and (条件1)and(条件2){ CSS选择器{ CSS属性:属性值 } } ...
- 浅尝Java(二、代码折叠插件的使用)
主题:eclipse代码折叠插件的使用. 工作中在使用eclipse开发Java项目时,我们会写很多if,for循环啊什么的,这使得我们的项目代码会有很多很多行.写完后要想检查或者查看,就要从头一行一 ...
- Vue自定义事件
前面的话 父组件使用props传递数据给子组件,子组件怎么跟父组件通信呢?这时,Vue的自定义事件就派上用场了.本文将详细介绍Vue自定义事件 事件绑定 每个 Vue 实例都实现了事件接口 (Even ...
- CSSc常用样式
一.CSS常用文本属性 1.css中的颜色表示方式 1.1直接使用颜色的单词表示:red.green.blue 1.2使用颜色的十六进制表示:#ff0000,#00ff00: ...
- Go语言数组的使用
Go 语言数组 Go 语言提供了数组类型的数据结构. 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形.字符串或者自定义类型. 相对于去声明number0 ...
- 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——收流篇:(三)RTSP命令解析
一.RTSP命令简述 RTSP是用来控制实时流媒体“播放”.“暂停”.“停止”.“录像”等行为的传输协议.该协议规定了一系列命令以及这些命令的发送格式,RTSP客户端可以通过发送这些指定的命令,从而控 ...