可变参数函数初步分析

来源:互联网 发布:初级数据分析工程师 编辑:程序博客网 时间:2024/05/22 04:52

在函数的原型中,列出了函数期望接受的参数,但函数只能显示固定数目的参数,让一个函数在不同的时候接受不同的数目参数是不是可以呢?答案是肯定的,但存在一些限制.

stdarg宏
可变参数列表是通过宏来实现的,这些宏定义于stdarg.h头文件中,它是标准库的一部分.这个头文件声明一个类型va_list,三个宏va_start,va_arg,和va_end

接下来分析它们的作用和原理

typedef char *  va_list

va_list=char*
(va_list ap)
开始需声明一个va_list类型的指针ap,它用于访问参数列表的未知部分

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

其中v表示距离未知参数列表最近的确定参数.
(va_list)&v 取出v的地址,强转成于ap同一类型
ap=(va_list)&v+_INTSIZEOF(v) 让ap指向未知参数列表中的第一个参数

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

_INTSIZEOF(v):将v的字节数进行整形提升,当v的字节数为1,2,3,4则表示4个字节,
当字节数为9,10,11,12则表示为12个字节依此类推
整个宏的意义在于对ap进行初始化,使得ap指向参数列表第一个参数

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

其中i为参数类型
逐步分析
(ap += _INTSIZEOF(t):使得ap指向第二个参数
((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))将整个表达式的指向第一个参数
(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))将表达式指针类型强制转换成参数类型
(t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) 对整个表达式解引用,表示第一个参数
此时宏表示第一个参数,而ap指向第二个参数,再次进行宏替换时,宏又表示第二个参数,十分巧妙.

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

结束前,将ap赋值空.


可变参数的限制
注意,可变参数必须从头到尾逐个访问.可半途终止,但不可从任意位置开始访问.
1.参数列表至少有一个命名参数(确定参数),才能使用va_start给指针ap初始化(定位)
2.这些宏是无法直接判断实际存在参数的数量的.
3.这些宏无法判断每个参数的类型
4如果在va_arg中指定了错误的类型,那么后果是不可预测的

原创粉丝点击