您现在的位置是:首页 > 正文

定义可变参数的宏

2024-01-30 22:11:59阅读 0

像printf类的函数,如果代码中的比较多,且需要检查返回值时,没用到一个地方就添加一段返回值检查会比较烦,不添加,如果要求pclint扫描时会报warning 514。

为了方便,有两种方式,一种是封装自己的函数,一种是定义成宏。

封装成自己的函数的坏处时,函数里的输出如果使用 __LINE__   __FUNCTION__  等时,所有调用的地方都会是相同的。

所以,我这选择定义成宏。

先上代码,VS2010验证过:

#include "stdafx.h"
#include <stdio.h>

#define My_Print(format , ...)  printf(format, __VA_ARGS__)
#define My_sprintf_s(a,b,format,...) sprintf_s(a,b,format, __VA_ARGS__) 

int _tmain(int argc, _TCHAR* argv[])
{
	char cTemp[260] = {0};
	My_sprintf_s(cTemp, 260, "%s %d\n", "hello test", 7);
	My_Print(cTemp);
	My_Print("hello world\n");
	return 0;
}

运行结果:

解释:

C99中规定宏可以像函数一样带有可变参数,比如:

#define LOG(format, ...) fprintf(stdout, format, __VA_ARGS__)

其中,...表示参数可变,__VA_ARGS__在预处理中为实际的参数集所替换

GCC中同时支持如下的形式

#define LOG(format, args...) fprintf(stdout, format, args)

其用法和上面的基本一致,只是参数符号有变化

有一点需要注意,上述的宏定义不能省略可变参数,尽管你可以传递一个空参数,这里有必要提到"##"连接符号的用法。

"##"的作用是对token进行连接,在上例中,format、__VA_ARGS__、args即是token,

如果token为空,那么不进行连接,所以允许省略可变参数(__VA_ARGS__和args),对上述变参宏做如下修改

#define LOG(format, ...)     fprintf(stdout, format, ##__VA_ARGS__)
#define LOG(format, args...) fprintf(stdout, format, ##args)
 

上述的变参宏定义不仅能自定义输出格式,而且配合#ifdef #else #endif在输出管理上也很方便,

比如调试时输出调试信息,正式发布时则不输出,可以这样

#ifdef DEBUG
#define LOG(format, ...) fprintf(stdout, ">> "format"\n", ##__VA_ARGS__)
#else
#define LOG(format, ...)
#endif
在调试环境下,LOG宏是一个变参输出宏,以自定义的格式输出;

在发布环境下,LOG宏是一个空宏,不做任何事情。

网站文章

  • 单表查询student表和score

    单表查询student表和score

    Sutdent 表的定义字段名 字段描述 数据类型 (主键 外键 非空 唯一 自增)Id 学号 INT(10) 是否是是是Name 姓名 VARCHAR(20) 否否是否否Sex 性别 VARCHAR...

    2024-01-30 22:11:29
  • 宽度的100%和auto的区别

    前段时间做项目,发现分不清width设为100%和auto的区别,实在是太水了,就查了点资料,做个总结,有不对的地方欢迎大家指出。 width:auto 块级元素默认的宽度值。看一下MDN上的解释:The browser will calculate and select a width for the specified element.大意是浏览器会自己选择一个合适的宽度值,那么...

    2024-01-30 22:11:22
  • 股票配对交易策略-最小距离法

    股票配对交易策略-最小距离法

    策略配对交易( Pairs Trading)为这种困境提供了一种既能避险又盈利的策略,其又被称之为价差交易或者统计套利交易,是一种风险小、收益较稳定的市场中性策略。一般的做法,是在市场中寻找两只历史价...

    2024-01-30 22:11:15
  • 创建型设计模式(6种)学习

    创建型设计模式(6种)学习

    Linux服务器开发/后台架构师知识体系整理 创建型设计模式有: 共6种 简单工厂模式(Simple Factory) 工厂方法模式(Factory Method) 抽象工厂模式(Abstract F...

    2024-01-30 22:10:46
  • JS中的遍历循环

    JS中的遍历循环

    Object.keys(obj):参数:要返回其枚举自身属性的对象。返回值:一个表示给定对象的所有可枚举属性的数组。对象:返回可枚举的属性数组。var obj = { 'name' : 'zhangsan', 'age' : '18', 'language' : [1,[2,3],[4,5]], "fun":function(str){ ...

    2024-01-30 22:10:38
  • Dubbo 远程调用过程

    Dubbo 远程调用过程

    Dubbo远程调用过程。

    2024-01-30 22:10:32
  • Ubuntu中apache2(httpd)安装、httpd实现网页图片的挂载

    Ubuntu中apache2(httpd)安装、httpd实现网页图片的挂载

    一、apache2软件包安装和开启 (1)apache2安装 sudo apt-get update sudo apt-get install apache2 (2)apache2的开启 命令:sud...

    2024-01-30 22:10:25
  • Window.open()方法参数详解

    1, 最基本的弹出窗口代码 window.open(&#39;page.html&#39;);2, 经过设置后的弹出窗口 window.open(&#39;page.html&#39;, &#39;n...

    2024-01-30 22:09:56
  • vsinoplayer statemachine

    vsinoplayer statemachine

    2024-01-30 22:09:49
  • 数据业务建立流程之发起网络连接过程(原)

    数据业务建立流程之发起网络连接过程(原)

    经过前面这些过程,网络连接所需要的条件就全部准备就绪,接下来就是等待网络接入。 我们把网络接入过程简单分为三个阶段: 触发阶段 ----该阶段是由各种不同事件触发的,比如SIM载入完毕、PS域Attach成功、通话结束、APN改变等,该阶段的最终都是要调用setupDataOnConnectableApns()方法;

    2024-01-30 22:09:44