可变参函数的兑现
可变参函数的实现
C编译器通常提供了一系列处理这种情况的宏,以屏蔽不同的硬件平台造成的差异,
增加程序的可移植性。这些宏包括va—start、va—arg和va—end等。
这些在stdarg.h中可以找到。
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址
#define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效
为什么可以这么做呢,我们在调用函数的时候,会把函数的参数等信息压入栈空间。
最后一个参数
倒数第二个参数
...
第一个参数
函数返回地址
函数代码段
一般说来从下到上的空间地址值逐渐减小,这个跟平台有关的,不关我们的事,
如果有必要stdarg.h会帮我们处理平台相关的东西。看一个简单的使用例子。
#include <stdio.h> #include <stdarg.h> //va_start int sum(int num, ...) { va_list parg; int arg, s = 0; va_start(parg, num); for (int i = 0; i < num; ++i) { arg = va_arg(parg, int); s += arg; } va_end(parg); return s; } void addr(int a, int b) { printf("a's addr = %x\n", &a); printf("b's addr = %x\n", &b); } int main(int argc, char* argv[]) { addr(5, 6); printf("%d\n", sum(3, 5, 2, 9)); // 5 + 2 + 9 = 16 return 0; }
运行结果:
a's addr = 611a55bc
b's addr = 611a55b8
16