一 、__VA_ARGS__

P454 所讲printf()这些输出函数的参数是可变的,在调试程序时,可能希望定义参数为可变的输出函数,

那么可变参数宏会是一个选择,例如:

#define DEBUG(X, ...) printf("Message", #X,":" __VA_ARGS__)

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

//variadic.c----可变宏

#define DBG(format, ...) printf("Message"#format":File:%s, Line:%d, Function:%s" __VA_ARGS__,__FILE__, __LINE__ , __FUNCTION__)

int main(void)
{
   double x = 48;
   double y = 0;
   y = sqrt(x);


   DBG(1,"x=%g\r\n",x);
   DBG(2,"x=%.2f,y=%.4f\r\n",x,y);
   return 0;
}

二、若部分不支持__VA_ARGS__,可以采用下面方法

#define DEBUG_BUFFER_MAX_LENGTH 1024
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 );
}

int main(void)
{
   double x = 48;
   double y = 0;
   y = sqrt(x);


   printDebugMsg("x=%g\r\n",x);
   printDebugMsg("x=%.2f,y=%.4f\r\n",x,y);
   return 0;
}
 
 
三、可变参数(P487)
int SqSum(int n1, ...)
{
    va_list arg_ptr;
    int nSqsum = 0;
    int n = n1;
    va_start(arg_ptr,n1);

    while(n > 1)
    {
        nSqsum +=(n*n);
        n = va_arg(arg_ptr,int);
    }

    va_end(arg_ptr);

    return nSqsum;
}

int main(void)
{
    int nSqSum = SqSum(2,3,4,5,-1);
    printf("sqsum = %d\r\n",nSqSum);
    return 0;
}
int SqSum(int n1, ...)参数可以分为两部分:个数确定的固定参数和个数可变的可选参数。函数至少需要一个固定参数,固定参数的声明和普通函数一样;可选参数由于个数不确定,声明时用"…"表示。固定参数和可选参数公同构成一个函数的参数列表。

分析上面例程,来看看各个va_xx的作用:
va_list arg_ptr:定义一个指向个数可变的参数列表指针;
va_start(arg_ptr, argN):使参数列表指针arg_ptr指向函数参数列表中的第一个可选参数,说明:argN是位于第一个可选参数之前的固定参数,(或者说,最后一个固定参数;…之前的一个参数),函数参数列表中参数在内存中的顺序与函数声明时的顺序是一致的。如果有一va函数的声明是void va_test(char a, char b, char c, …),则它的固定参数依次是a,b,c,最后一个固定参数argN为c,因此就是va_start(arg_ptr, c).
 
va_arg(arg_ptr, type):返回参数列表中指针arg_ptr所指的参数,返回类型为type,并使指针arg_ptr指向参数列表中下一个参数。
va_copy(dest, src):dest,src的类型都是va_list,va_copy()用于复制参数列表指针,将dest初始化为src。
va_end(arg_ptr):清空参数列表,并置参数指针arg_ptr无效。
 
说明:指针arg_ptr被置无效后,可以通过调用va_start()、va_copy()恢复arg_ptr。每次调用va_start() / va_copy()后,必须得有相应的va_end()与之匹配。参数指针可以在参数列表中随意地来回移动,但必须在va_start() … va_end()之内。

C Primer Plus(第五版)学习笔记-可变宏:...和__VA_ARGS__的更多相关文章

  1. Primer C++第五版 读书笔记(一)

    Primer C++第五版 读书笔记(一) (如有侵权请通知本人,将第一时间删文) 1.1-2.2 章节 关于C++变量初始化: 初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义 ...

  2. C++Primer第五版学习笔记

    <C++ Primer>Learning Note 程序实例下载地址:http://www.informit.com/title/0321714113 第一章            开始 ...

  3. PMBOK(第五版)学习笔记二-十大知识领域(P87)

    五大项目管理过程组:启动.规划.执行.监控.收尾过程组 十大知识领域是:项目整合管理.项目范围管理.项目时间管理.项目成本管理.项目质量管理.项目人力资源管理.项目沟通管理.项目风险管理.项目采购管理 ...

  4. 《C++Primer》第五版习题答案--第三章【学习笔记】

    [C++Primer]第五版[学习笔记]习题解答第三章 ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2020/1/10 第三章:字符串,向量和数组 ...

  5. 《C++Primer》第五版习题解答--第四章【学习笔记】

    [C++Primer]第五版习题解答--第四章[学习笔记] ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2020/1/11 第四章:表达式 练习4. ...

  6. 《C++Primer》第五版习题答案--第五章【学习笔记】

    <C++Primer>第五版习题答案--第五章[学习笔记] ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2020/1/15 第五章:语句 ...

  7. 《C++Primer》第五版习题答案--第六章【学习笔记】

    <C++Primer>第五版习题答案--第六章[学习笔记] ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2020/1/16 第六章:函数 ...

  8. C++Primer第5版学习笔记(四)

    C++Primer第5版学习笔记(四) 第六章的重难点内容         你可以点击这里回顾第四/五章的内容       第六章是和函数有关的知识,函数就是命名了的代码块,可以处理不同的情况,本章内 ...

  9. C++Primer第5版学习笔记(三)

    C++Primer第5版学习笔记(三) 第四/五章的重难点内容           你可以点击这里回顾第三章内容       因为第五章的内容比较少,因此和第四章的笔记内容合并.       第四章是 ...

随机推荐

  1. CentOS中操作

    在Centos中yum安装和卸载软件的使用方法安装方法安装一个软件时 :yum -y install httpd安装多个相类似的软件时:yum -y install httpd*安装多个非类似软件时 ...

  2. Pull Requests

    Contribution Guide Issue Tracker You can find outstanding issues on the GitHub Issue Tracker. Pull R ...

  3. 简单改写SQL达到优化目的

    select * from (select t.row_id, t.supplier_name, t.tel, address, t.contact, t.contact_post, t.contac ...

  4. JavaScript中的各种宽高以及位置总结

    JavaScript中的各种宽高以及位置总结 在javascript中操作dom节点让其运动的时候,常常会涉及到各种宽高以及位置坐标等概念,如果不能很好地理解这些属性所代表的意义,就不能理解js的运动 ...

  5. CSS3——选项卡切换

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. focus on these tools

    http://www.oschina.net/p/dubbo http://www.blogjava.net/hispark/archive/2008/12/01/243310.html http:/ ...

  7. 【区间覆盖问题】uva 10020 - Minimal coverage

    可以说是区间覆盖问题的例题... Note: 区间包含+排序扫描: 要求覆盖区间[s, t]; 1.把各区间按照Left从小到大排序,如果区间1的起点大于s,则无解(因为其他区间的左起点更大):否则选 ...

  8. [转]Spring数据库读写分离

    数据库的读写分离简单的说是把对数据库的读和写操作分开对应不同的数据库服务器,这样能有效地减轻数据库压力,也能减轻io压力. 主(master)数据库提供写操作,从(slave)数据库提供读操作,其实在 ...

  9. uiautomator的坑和AAPT命令方式启动一个应用程序

    最近在使用UIautomator完成公司的一个主流程的自动化,因为不适用H5和IOS所以会放弃这个工具的使用,现在记录在使用uiautomator的一些问题: 案列1:使用命令去启动要运用的apk包 ...

  10. Android -tool工具UIautomatorviewer提示“不能让屏幕黑屏”

    Android中有很多工具可以让我们使用,我使用比较多的有属DDMS,UIautomatorviewer,DDMS中信息也很强大,有空的时候在理理 这篇博主写的很详细:http://www.cnblo ...