一 、__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. C# 指针(unsafe与fixed的使用)

    c#在默认情况下生成的都是安全代码,即进行了代码托管(.NET的CLR机制好处之一是,进行代码托管,适时的释放内存,程序员便不必考虑资源的回收问题),而此时,指针不能出现在安全代码的编译条件下. 一. ...

  2. python--字符工厂函数dict()

    字符工厂函数str() class str(object): """ str(object='') -> str str(bytes_or_buffer[, enc ...

  3. Windows批处理(cmd/bat)常用命令小结

    转载自:“趣IT”微信公共号 前言 批处理文件(batch file)包含一系列 DOS命令,通常用于自动执行重复性任务.用户只需双击批处理文件便可执行任务,而无需重复输入相同指令.编写批处理文件非常 ...

  4. Enable HTTPS in Spring Boot

    Spring-boot-enable-ssl Enable HTTPS in Spring Boot APRIL 14, 2015DRISS AMRI This weekend I answered ...

  5. ssh用root直接登录失败的问题

    解决方法: 1) 以root身份,chmod +w /etc/ssh/sshd_config 2) vi /etc/ssh/sshd_config 3) 将PermitRootLogin no改成Pe ...

  6. mapping 详解4(mapping setting)

    mapping type 映射设置一般发生在: 1. 增加新的 index 的时候,添加 mapping type,对 fields 的映射进行设置 PUT twitter { "mappi ...

  7. DHCP 服务器

    简介: DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一个局域网的网络协议,使用UDP协议工作,主要用途:给内部网络或网络服务供应商自动分配 I ...

  8. SpringMVC与Struts2配置区别

     Spring MVC模型与Struts2模型应用:  Html表单: 上述这两段代码无论是SpringMVC还是Struts2,都可以共用.而在请求响应处理类(也就是Controller)上的设计差 ...

  9. css3过度和动画

    一.过度(transition) transition:[transition-property] || [transition-duration] || [transition-timing-fun ...

  10. SQL 分组后取最小行号记录

    本示例测试两个表联接查询后,分组并取分组后的最小行号记录 测试表: tb1表结构如下: CREATE TABLE [dbo].[tb1]( ) NOT NULL, ) NULL, ) NULL, CO ...