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