变参函数和va_list

来源:互联网 发布:k30平板荷载试验算法 编辑:程序博客网 时间:2024/06/05 12:23

此乃讨论贴。首先介绍下我的理解。变参函数参数看起来是这样

<函数返回值类型> 函数名 (固定形参1,固定形参2,...)比如

声明

void multiply (int factor1, int factor2, ...)

函数体

void multiply (int factor1, int factor2, ...)  

{

}

在调用他的函数里

multiply(1,2,3,4);      /*多少都行,但必须至少是2个,因为声明里固定参数有2个*/

多出来的两个参数,需要用到一种特殊的数据类型来访问(也有其他方法)

void multiply (int factor1, int factor2, ...)  

{

va_list ap;        /* va_list 类型变量ap,其实木有啥,就是一正常的指针类型变量,赋值后应该是指向参数列表,以后个就用ap指针来访问变参了,跟其他指针         * 类型变量声明一样,他现在没有指向任何地方*/

va_start (ap, factor2);   /* ap现在指向 factor2后面的一个参数了,va_start作用只是指针ap赋值这里小啰嗦一下,va_start赋值时,应当是指向最后一个固定参数(这里 * 是factor2,factor1是第一个固定参数)因为只有变参才需要指针访问他,固定参数直接用参数名就好了嘛*/

int factor3 = *((int *)ap);

factor3 = va_arg(ap, int); /* 这两种方法factor3值相同,不同的是va_arg返回的值是ap当前,并且将ap指向下一个参数,通过的方法是*ap++ */

...

va_end(ap)    /* ap再也不用了*/

}


最近查阅了几个博文关于变参函数和va_list 的使用,发现有一些矛盾之处。

首先是堆栈中参数存储顺序。根据

http://blog.csdn.net/zckloveczy/article/details/4260698

高地址 最后一个参数

倒数第二个参数

...

第一个参数

函数返回地址

低地址 函数体


然后根据

http://wenku.baidu.com/view/e79b720f52ea551810a68783.html

高地址 函数返回地址

最后一个参数

倒数第二个参数

...

低地址 第一个参数


这两处矛盾在于函数返回地址和参数列表比,谁的地址更高?


第二个有趣的现象是,va_end 这个宏,我觉得他应该是像delete一样,先把指针删了,再指向null,可代码中,他什么都没有做。并且当我用完va_end(ap)后,用*((int *)ap)居然能看到他的值


在VC++6.0的include有一个stdarg.h头文件,有如下四个宏定义:

#define _INTSIZEOF(n)   ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 

/* int型占的字节数,不大于4的是4,大于4小于等于8的是8 */


#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )           

/* v是最后一个固定参数,加上他按int字节数对齐后,就是第一个可选参数地址 */


#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

/* 第一步ap += _INTSIZEOF(t),ap指向下一个形参,命名为n,第二步,将当前参数的值返回 */


#define va_end(ap)    ( ap = (va_list)0 )                            // 将指针置为无效



在内核的文件里

#define va_arg(ap, T)           (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap)              (void) 0
#define va_start(ap, A)         (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))

原创粉丝点击