可变参数列表

Posted _NiuLi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可变参数列表相关的知识,希望对你有一定的参考价值。

在很长的一段时间里,我都感觉可变参数列表难!很难! 

今天又遇到了这个难题。起因是要写一个求和的函数,函数的参数不确定。这就需要使用可变参数列表来实现。然我写不出来。脾气上来了决定好好研究一下这个,然后开始查源码,研究了一下突然发现好简单……

可变参数列表是怎么实现的呢?举个例子可能更好理解

现在需要写一个对参数求和的函数,传入的参数不确定。参数原型 int Sum(size_t N,  ...);

接下来需要知道实现可变参数的工具:一个类型va_list,三个宏va_start、 va_arg、 va_end。不要被这四个单词吓着了(虽然今天之前我也是这样)。

va_list:

它的真面目是这样的, typedef char*   va_list;说白了它就是一个char * ,用来定义变量访问访问可变参数。

va_list arg;


va_start:

va_start(arg,N); 
va_start的作用是将arg指向可变参数部分的第一个参数。比如Sum(3,1,2,3); va_start 会将arg指向1。具体操作如下:

(1)拿到N的地址,强转为va_list类型,然后赋给arg

(2)arg向后偏移N的大小个字节,指向N后面的参数,即可变参数的第一个参数

vs2013中的源码是这样的:

#define  va_start   _crt_va_start
#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _ADDRESSOF(v)   ( &(v) )
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )<span style="font-size: 12px; font-family: Arial, Helvetica, sans-serif;">//这样写是为了字节对齐,详解http://www.cnblogs.com/diyunpeng/archive/2010/01/09/1643160.html</span>

 

va_arg:

ret += va_arg(arg, int);

va_arg会返回当前arg指向的参数的值,同时会让arg指向下一个参数。具体操作如下:

(1)让arg指向下一个参数,即arg+=sizeof(int);

(2)返回arg之前指向的参数的值,即 *(int*)(arg - sizeof(int))

vs2013中的代码:

#define va_arg   _crt_va_arg
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )


va_end:

va_end(arg);
将arg赋为NULL,防止野指针

#define va_end   _crt_va_end
#define _crt_va_end(ap)      ( ap = (va_list)0 )

so 函数Sum的完整实现如下:

int Sum(size_t N, ...)

	int ret = 0;
	va_list arg;
	va_start(arg, N);
	while (N--)
	
		ret += va_arg(arg, int);
	

	va_end(arg);
	
	return ret;




以上是关于可变参数列表的主要内容,如果未能解决你的问题,请参考以下文章

15 可变参数列表

16 可变参数列表和重载问题(最后选择可变参数列表)

C语言 可变参数列表

golang中可变长参数的使用

golang中可变长参数的使用

Java 可变参数列表