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 为结束符。

c(++)变长参数之整形(非字符串类型类似)的更多相关文章

  1. C++中的变长参数

    新参与的项目中,为了使用共享内存和自定义内存池,我们自己定义了MemNew函数,且在函数内部对于非pod类型自动执行构造函数.在需要的地方调用自定义的MemNew函数.这样就带来一个问题,使用stl的 ...

  2. Java基础12-工具类;变长参数;IO

    作业解析 取出整数的16进制表示形式 \u00ff /** * int2hex * */ public static String int2hex(int i) { String str = &quo ...

  3. 《OOC》笔记(3)——C语言变长参数va_list的用法

    <OOC>笔记(3)——C语言变长参数va_list的用法 C语言中赫赫有名的printf函数,能够接受的参数数目不固定,这就是变长参数.C#里也有params这个关键字用来实现变长参数. ...

  4. (一)预定义宏、__func__、_Pragma、变长参数宏定义以及__VA_ARGS__

    作为第一篇,首先要说一下C++11与C99的兼容性. C++11将 对以下这些C99特性的支持 都纳入新标准中: 1) C99中的预定义宏 2) __func__预定义标识符 3) _Pragma操作 ...

  5. c++11变长参数函数模板

    By francis_hao    Mar 25,2018   一个最简单的实例大概是这个样子: #include <iostream>using namespace std; /*变长参 ...

  6. Scala 变长参数

    如果Scala定义变长参数 def sum(i Int*), 那么调用sum时,可以直接输入sum(1,2,3,4,5) 但是不可以sum(1 to 5) 必须要将1 to 5 强制为seq sum( ...

  7. C++11变长参数模板

    [C++11变长参数模板] C++03只有固定模板参数.C++11 加入新的表示法,允许任意个数.任意类别的模板参数,不必在定义时将参数的个数固定. 实参的个数也可以是 0,所以 tuple<& ...

  8. 【Unix环境高级编程】编写变长参数函数

    文件的格式输入输出函数都支持变长参数.定义时,变长参数列表通过省略号'...'表示, 因此函数定义格式为: type 函数名(parm1, parm2,parmN,...); Unix的变长参数通过v ...

  9. java常量和变量的定义规则,变长参数的使用

    首先是定义的一般规则,类名首字母全部大写,常量全部大写用下划线分隔,变量用驼峰形式.注意使用long赋值用L时不能写小写的L要写大写的,不然会和数字“1”傻傻分不清. 下面是举例: public cl ...

随机推荐

  1. UOJ #228 - 基础数据结构练习题(势能线段树+复杂度分析)

    题面传送门 神仙题. 乍一看和经典题 花神游历各国有一点像,只不过多了一个区间加操作.不过多了这个区间加操作就无法再像花神游历各国那样暴力开根直到最小值为 \(1\) 为止的做法了,稍微感性理解一下即 ...

  2. 力扣 - 剑指 Offer 47. 礼物的最大价值

    题目 剑指 Offer 47. 礼物的最大价值 思路1 因为是要求最大价值,而且只能移动下方或者右方,因此,每个位置的最大值就是本身的值加上上边 / 左边 中的最大值,然后每次遍历都可以复用上一次的值 ...

  3. [源码解析] PyTorch 分布式 Autograd (4) ---- 如何切入引擎

    [源码解析] PyTorch 分布式 Autograd (4) ---- 如何切入引擎 目录 [源码解析] PyTorch 分布式 Autograd (4) ---- 如何切入引擎 0x00 摘要 0 ...

  4. 【samtools】运行报错: error while loading shared libraries:libcrypto.so.1.0.0或libncurses.so.5或libtinfow.so.5

    samtools用conda安装后,总是出现共享库缺失的报错.即便你刚安装samtools时可以用,但后面在同一环境中安装其他相关软件,有可能产生了冲突,导致库替换,因而报错. 避免这种情况,可能最好 ...

  5. R 语言实战-Part 3 笔记

    R 语言实战(第二版) part 3 中级方法 -------------第8章 回归------------------ #概念:用一个或多个自变量(预测变量)来预测因变量(响应变量)的方法 #最常 ...

  6. eclipse 配置黑色主题(转载)

    转载:http://www.cnblogs.com/csulennon/p/4231405.html 虽然以前也使用eclipse的黑色主题,但是配置起来稍微麻烦一点. 这里先声明,下面的方式适合最新 ...

  7. zabbix 内网机器通信状态

    a=0 for xgip in ${xgipset[*]} do let a+=1 fping $xgip|grep alive >/dev/null if [ $a != 3 ];then i ...

  8. 9 — springboot整合jdbc、druid、druid实现日志监控 — 更新完毕

    1.整合jdbc.druid 1).导入依赖 <dependency> <groupId>org.springframework.boot</groupId> &l ...

  9. RTSP, RTP, RTCP, RTMP傻傻分不清?

    RTSP基于TCP传输请求和响应报文,RTP基于UDP传输流媒体数据,RTCP基于UDP传送传输质量信息(如丢包和延迟). 比如喀什一个局域网内10个人同时点播广州的同一个源,喀什和广州之间就要传10 ...

  10. 并发 并行 进程 线程 协程 异步I/O python async

    一些草率不精确的观点: 并发: 一起发生,occurence: sth that happens. 并行: 同时处理. parallel lines: 平行线.thread.join()之前是啥?落霞 ...