__VA_ARGS__用法

2023-11-09

自定义调试信息的输出
  调试信息的输出方法有很多种,  例如直接用printf,  或者出错时使用perror, fprintf等将信息直接打印到终端上, 在Qt上面一般使用qDebug,而守护进程则一般是使用syslog将调试信息输出到日志文件中等等...
  使用标准的方法打印调试信息有时候不是很方便,  例如Qt编程, 在调试已有的代码时, 我想在打印调试信息的地方, 把代码位置也打印出来以方便定位错误, 或者需要在调试信息前面加一个前辍, 好方便在调试信息太多的时候可以用grep过滤一下, 仅显示本模块的调试信息, 这时就需要一个一个地修改已有的qDebug, 使其成为以下形式:
  qDebug( "[模块名称] 调试信息  File:%s, Line:%d", __FILE__, __LINE__ );
  这样的修改比较烦人, 而且一不小心会遗漏某个没改的...
  为了能方便地管理调试信息的输出,一个比较简单的方法就是自已定义一个打印调试信息的宏, 然后替换原来的,废话就不多说了,直接给出一个现成的,下面是一个例子, 我用WiFi表示当前代码的模块名称,我要求在模块中的所有调试信息前面均带有[WiFi]前辍,这样我就能方便地只需使用命令行 | grep "\[WiFi\]"来过滤掉来自其它模块的调试信息了:
#define qWiFiDebug(format, ...) qDebug("[WiFi] "format" File:%s, Line:%d, Function:%s", ##__VA_ARGS__, __FILE__, __LINE__ , __FUNCTION__);
  上面的宏是使用qDebug输出调试信息,在非Qt的程序中也可以改为printf,守护进程则可以改为syslog等等...  其中,决窍其实就是这几个宏 ##__VA_ARGS__, __FILE__, __LINE__ 和__FUNCTION__,下面介绍一下这几个宏:
  1)  __VA_ARGS__ 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用,否则会编译出错, 你可以试试。
  2) __FILE__ 宏在预编译时会替换成当前的源文件名
  3) __LINE__宏在预编译时会替换成当前的行号
  4) __FUNCTION__宏在预编译时会替换成当前的函数名称
  有了以上这几个宏,特别是有了__VA_ARGS__ ,调试信息的输出就变得灵活多了。
  有时,我们想把调试信息输出到屏幕上,而有时则又想把它输出到一个文件中,可参考下面的例子:
//debug.c
#include <stdio.h>
#include <string.h>
//开启下面的宏表示程序运行在调试版本, 否则为发行版本, 这里假设只有调试版本才输出调试信息
#define _DEBUG
#ifdef _DEBUG
    //开启下面的宏就把调试信息输出到文件,注释即输出到终端
    #define DEBUG_TO_FILE
    #ifdef DEBUG_TO_FILE
        //调试信息输出到以下文件
        #define DEBUG_FILE "/tmp/debugmsg"
        //调试信息的缓冲长度
        #define DEBUG_BUFFER_MAX 4096
        //将调试信息输出到文件中
        #define printDebugMsg(moduleName, format, ...) {\
            char buffer[DEBUG_BUFFER_MAX+1]={0};\
            snprintf( buffer, DEBUG_BUFFER_MAX \
                    , "[%s] "format" File:%s, Line:%d\n", moduleName, ##__VA_ARGS__, __FILE__, __LINE__ );\
            FILE* fd = fopen(DEBUG_FILE, "a");\
            if ( fd != NULL ) {\
                fwrite( buffer, strlen(buffer), 1, fd );\
                fflush( fd );\
                fclose( fd );\
            }\
        }
    #else
        //将调试信息输出到终端
        #define printDebugMsg(moduleName, format, ...) \
                  printf( "[%s] "format" File:%s, Line:%d\n", moduleName, ##__VA_ARGS__, __FILE__, __LINE__ );
    #endif //end for #ifdef DEBUG_TO_FILE
#else
    //发行版本,什么也不做
    #define printDebugMsg(moduleName, format, ...)
#endif  //end for #ifdef _DEBUG
int main(int argc, char** argv)
{
    int data = 999;
    printDebugMsg( "TestProgram", "data = %d", data );
    return 0;
}
 
 
  上面也说了,只有支持C99规范的gcc编译器才有__VA_ARGS__这个宏,如果不是gcc编译器,或者所用的gcc编译器版本不支持__VA_ARGS__宏怎么办? 可参考下面的代码片段,我们换一种做法,可先将可变参数转换成字符串后,再进行输出即可:
void printDebugMsg( const char* format, ...)
{
    char buffer[DEBUG_BUFFER_MAX_LENGTH + 1]={0};
    va_list arg;
    va_start (arg, format);
    vsnprintf(buffer, DEBUG_BUFFER_MAX_LENGTH, format, arg);
    va_end (arg);
    printf( "%s", buffer );
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

__VA_ARGS__用法 的相关文章

随机推荐

  • 【Freesql】实现动态分组(groupby)

    应用场景 分组条件是a b c d的任意组合 来自前端 前端选了 a就只分组a 选了 a b就分组a b 请问怎么用freesql写出来 select 部分也是来自前端 前端选了 a就只查a 选了 a b就只查a b select a b
  • ubuntu python3安装opencv_ubuntu中给python3安装opencv

    一 安装相关工具包 注意 以下3 4 5 6为可选项 根据需求安装 1 更新库 sudo apt get update sudo apt get upgrade 2 安装从源码构建opencv的相关工具 sudo apt get insta
  • flutter 更改CircleProgressIndicator的颜色

    在flutter中 CircleProgressIndicator 默认颜色为 主题设定的颜色 CircleProgressIndicator的参数有3种 value 0 1的浮点数 用来表示进度多少 valueColor 是animati
  • 云原生Docker搭建chemex资产管理系统

    这篇文章主要讲解如何使用Ubuntu系统安装Docker应用并且搭建Chemex资产管理系统 Chemex数据是存在数据库的 为了方便备份以及管理容器 可利用外部的数据库或者Docker搭建一个数据库出来 我这里就在Docker容器中创建一
  • python单选题考试题目大全

    在Python中要生成随机数 应该使用 A math 模块 B random模块 正确答案 C numpy 模块 D pygame 模块 关于函数的下列说法不正确的是 A 函数可以没有参数 B 函数可以有多个返回值 正确答案 C 函数可以没
  • edge浏览器 您的flash可能被禁用或者版本过低

    转自 http blog sina com cn s blog 540316260102xkp1 html 从Win 8开始 微软的Windows操作系统就已经将Flash Player内嵌 故对于Win 10系统使用微软默认的Edge浏览
  • C# Http文件上传-简单版

    C HttpClient public static async Task
  • servlet配置小程序服务器,servlet配置小程序服务器

    servlet配置小程序服务器 内容精选 换一换 微架构分析基于ARM PMU Performance Monitor Unit 事件 获得指令在CPU流水线上的运行情况 可以帮助用户快速定位当前应用在CPU上的性能瓶颈 因此用户便可以有针
  • Selenium基础 — 单选按钮和多选按钮的操作

    1 页面中的单选按钮和多选按钮 页面中的单选按钮和多选按钮样式如下图 页面代码片段 fieldset legend 单选按钮radio legend fieldset
  • 【Python】Python读取CSV文件

    CSV文件是一种常见的数据存储格式 很多人在日常工作中需要使用Python处理CSV文件 Python提供了多种方法来读取CSV文件 包括使用标准库 第三方库和内置函数 本文将介绍多种Python读取CSV文件的方法 使用Python内置c
  • 在Ubuntu上配置Redis服务器参数

    Redis的默认配置位于 etc redis redis conf中 如果权限不足 修改权限即可 chmod 777 redis conf vim etc redis redis conf 1 用守护线程的方式启动redis daemoni
  • 出栈顺序问题讲解 蓝桥杯

    引言 最近刷数据结构的题 刷到一组元素入栈 他的出栈顺序有可能是哪些时卡住 之前没有关注此类问题 便写下总结 先通过几个例题讲解下出栈顺序问题 1 一个栈的入栈序列是a b c d e则栈的不可能的输出序列是 A edcba B decba
  • vs中readfile的作用_低调看JRS直播:NBA直播-湖人vs灰熊 掘金vs雷霆 马刺vs爵士视频直播地址...

    北京时间2月22日 2019 20赛季NBA常规赛将继续进行 24vs直播将为您直播9场精彩比赛 敬请关注 以下是22日比赛的赛点汇总 比赛类型 NBA 比赛时间 2020年2月22日 直播对阵 8点骑士vs奇才 8点独行侠vs魔术 8点3
  • Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationEx...

    1 Caused by org springframework boot autoconfigure jdbc DataSourceProperties DataSourceBeanCreationException Cannot dete
  • glob函数的使用

    glob库函数用于Linux文件系统中路径名称的模式匹配 即查找文件系统中指定模式的路径 注意 这不是正则表达式匹配 虽然有些相似 但还是有点差别 glob函数原型 include
  • Mybatis常见查询操作——mybatis parameterType 传入多个参数

    书接上文 Mybatis常见查询操作 https blog csdn net weixin 43388691 article details 127211492 spm 1001 2014 3001 5502 这篇文章我们接着探讨Mybat
  • 12岁学编程

    学习编程的孩子越来越多 格物斯坦小坦克来分析原因 一是家长的意识已经有了很大提升 越来越注重孩子科学素养的培养教育 二来少儿编程课程本身的趣味性 让孩子接触学习起来没有压力感 乐于被孩子接受 说明编程学习对于孩子而言是可以接受的 儿童编程入
  • 世界各个地区WIFI 2.4G及5G信道划分表(附无线通信频率分配表)

    目前主流的无线WIFI网络设备802 11a b g n ac 传统 802 11 1997年发布 两个原始数据率 1Mbps 和 2Mbps 跳频展频 FHSS 或直接序列展布频谱 DSSS 三个不重叠的信道中 工业 科学 医学 ISM
  • 用Spring Boot开发你的第一个web应用程序

    26 开发Web应用 Spring Boot非常适合开发web应用程序 你可以使用内嵌的Tomcat Jetty或Undertow轻轻松松地创建一个HTTP服务器 大多数的web应用都使用spring boot starter web模块进
  • __VA_ARGS__用法

    自定义调试信息的输出 调试信息的输出方法有很多种 例如直接用printf 或者出错时使用perror fprintf等将信息直接打印到终端上 在Qt上面一般使用qDebug 而守护进程则一般是使用syslog将调试信息输出到日志文件中等等