0、序言

  变长参数,接触的第一个可变长参数函数是 printf   , 然后是 scanf   。他们的原型如下:

printf:

_Check_return_opt_
_CRT_STDIO_INLINE int __CRTDECL printf(
_In_z_ _Printf_format_string_ char const* const _Format,
...)

scanf

_CRT_STDIO_INLINE int __CRTDECL scanf(
_In_z_ _Scanf_format_string_ char const* const _Format,
...)

  本文演示的是数据类型是 int .

1、使用

  A、头文件

// 使用va_start需要的头文件
#include <stdarg.h>

  B、使用必须使用的4个宏,原型就不贴出来了,大家更关心的是怎么使用。:

  va_list :保存可变长参数

  va_start:构建一个参数集合

  va_arg:获取集合中的参数

  va_end:释放集合

  C、和普通参数使用相似,第一个参数必须要指定为类型,后面 写三个 点。例如:

vodi add(const int param, ...);

 

2、一个完整的例子  

  演示环境: VS2015 up3

  这里,定义了一个函数,函数用来求和,参数类型为整形,参数为可变长参数

 1 #include <iostream>
2
3 // 使用va_start需要的头文件
4 #include <stdarg.h>
5
6 // 不定长参数求和
7 void va_sum(const int first_param, ...)
8 {
9
10 va_list ap;
11
12 va_start(ap, first_param);
13
14 // 保存求和的结果, 演示不定长参数用法,暂时不考虑越界
15 int sum = 0;
16
17 // 中间每一项
18 int tmp = 0;
19
20 // -1 表示 集合的结束
21 for (int i = 0; -1 != tmp ; i++)
22 {
23 // 显示第i个参数
24 std::cout << "i=" << i << ", tmp=" << tmp << "\n";
25 // 保存结果
26 sum += tmp;
27 // 找到下一个参数
28 tmp = va_arg(ap, int);
29
30 }
31
32 // 释放空间
33 va_end(ap);
34
35 // 输出结果
36 std::cout << "sum = " << sum << "\n";
37 }
38
39 // 入口函数
40 int main(int argc, char *argv[])
41 {
42 // -1 表示可变长参数的结束
43 va_sum(1, 2, 3, 4, -1);
44
45 system("pause");
46 return 0;
47 }

  这段代码,大家先看下, 预测下 sum 的输出结果。 下面将有正确答案。

  我第一次作答的答案: 函数 va_sum   用来求和的, main函数传入了参数: 1. 2. 3. 4. -1.  所以, va_sum中的sum=1 + 2 + 3 + 4 = 10。 sum将输出 10。

  正确答案是:

   sum 怎么不是10 ? 怎么i= 0,输出的不是第一个参数1, 而是 2?

  踩坑:检查发现, sum 少加了 参数 1。 阅读上面的代码,不难发现, 当 第一次 调用 va_arg 宏时, 此时得到的是集合的第1个参数,而不是调用传入的参数1. 1 是第一个参数。

   具体,咱们看下  va_start,  va_end, va_arg的宏定义(来自Vs2015up3中vadefs.h文件的定义)

1    #define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)))
2 #define __crt_va_arg(ap, t) (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
3 #define __crt_va_end(ap) ((void)(ap = (va_list)0))

  明白了。

  怎么改实现求和? sum 加上 第一个参数 :first_param 即可。va_sum 函数的for循环前增加一行代码:

// 新增加
sum += first_param;

  va_sum函数完整定义:

 1 // 不定长参数求和
2 void va_sum(const int first_param, ...)
3 {
4
5 va_list ap;
6
7 va_start(ap, first_param);
8
9 // 保存求和的结果, 演示不定长参数用法,暂时不考虑越界
10 int sum = 0;
11
12 // 中间每一项
13 int tmp = 0;
14
15 // 新增加
16 sum += first_param;
17
18 // -1 表示 集合的结束
19 for (int i = 0; -1 != tmp ; i++)
20 {
21 // 显示第i个参数
22 std::cout << "i=" << i << ", tmp=" << tmp << "\n";
23 // 保存结果
24 sum += tmp;
25 // 找到下一个参数
26 tmp = va_arg(ap, int);
27
28 }
29
30 // 释放空间
31 va_end(ap);
32
33 // 输出结果
34 std::cout << "sum = " << sum << "\n";
35 }

  输出结果:

3、总结

  A、第一次调用 va_arg 指向的是集合的第一个元素,而不是调用时传入的第一个参数。

  B、va_list 保存的时 函数参数 三个点【...】的参数,调用时传入的第一个参数保存在函数的第一个参数中。

  C、 va_start 与 va_end 需要配对使用。

  D、需要指定结束符。 这里 -1 为结束符。

最新文章

  1. 在jexus下如何简单的配置多站点
  2. 在SQL存储过程中给条件变量加上单引号
  3. URAL 1780 G - Gray Code 找规律
  4. CSS——LESS
  5. JQeury Image LazyLoad
  6. UWP 手绘视频创作工具技术分享系列 - 有 AI 的手绘视频
  7. socket编程: TypeError: must be bytes or buffer, not str
  8. Simple scatter method in 2d picture(Qt)
  9. USE &quot; cc.exports.* = value &quot; INSTEAD OF SET GLOBAL VARIABLE&quot;
  10. CBV源码解析
  11. react-static 基于react 渐进式静态站点生成框架
  12. 【原创】基于Bootstrap的Modal二次封装
  13. 月之数(hdu2502)数学题
  14. json字符串转JSONObject和JSONArray以及取值
  15. git statsh命令报错解决
  16. Streamr助你掌控自己的数据
  17. json的好处-新一代数据传输利器
  18. 求解任意图的最小支配集(Minimun Dominating Set)
  19. java网络通信:HTTP协议
  20. jquery cookie操作方法

热门文章

  1. EXCEL-COUNTIF()统计符合区间上的值个数
  2. Prometheus_exporter安装与使用
  3. Oracle——创建存储过程
  4. maven内存溢出解决方法
  5. mysql之join浅析
  6. Dubbo消费者异步调用Future使用
  7. 【编程思想】【设计模式】【结构模式Structural】享元模式flyweight
  8. Vue中的8种组件通信方式
  9. eclipse.ini顺序
  10. 【划重点】Python matplotlib绘图设置坐标轴的刻度