1 C 语言的可变参数 C 语言中有些函数使用可变参数,比如常见的int printf( const char* format, ...),第一个参数format 是固定的,其余的参数的个数和类型都不固定。VA 函数(variable argument function),参数个数可变函数,又称可变参数函数。C/C++编程中,系统提供给编程人员的va 函数很少。*printf()/*scanf()系列函数,用于输入输出时格式化字符串;exec*()系列函数,用于在程序中执行外部文件(main(int argc,char*argv[]算不算呢,与其说 main()也是一个可变参数函数,倒不如说它是exec*()经过封装后的具备特殊功能和意义的函数,至少在原理这一级上有很多相似之处)。由于参数个数的不确定,使va 函数具有很大的灵活性,易用性,对没有使用过可变参数函数的编程人员很有诱惑力; C 语言用va_start 等宏来处理这些可变参数。这些宏看起来很复杂,其实原理挺简单,就是根据参数入栈的特点从最靠近第一个可变参数的固定参数开始,依次获取每个可变参数的地址。下面我们来分析这些宏。 在 stdarg.h 头文件中,针对不同平台有不同的宏定义,我们选取 X86 平台下的宏定义: typedef char * va_list; #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 ) _INTSIZEOF(n)宏是为了考虑那些内存地址需要对齐的系统,从宏的名字来应该是跟sizeof(int)对齐。一般的sizeof(int)=4,也就是参数在内存中的地址都为 4 的倍数。比如,如果 sizeof(n)在 1-4 之间,那么_INTSIZEOF(n)=4;如果 sizeof(n)在 5-8 之间,那么_INTSIZEOF(n)=8。 为了能从固定参数依次得到每个可变参数,va_start,va_arg 充分利用下面两点: 1. C 语言在函数调用时,先将最后一个参数压入栈 2. X86 平台下的内存分配顺序是从高地址内存到低地址内存 高位地址 第N 个可变参数 。。。 第二个可变参数 第一个可变参数 ? ap 固定参数 ? v 低位地址 由上图可见,v 是固定参数在内存中的地址,在调用va_start 后,ap 指向第一个可变参数。这个宏的作用就是在 v 的内存地址上增加 v 所占的内存大小,这样就得到了第一个可变参数的地址。 接下来,可以这样设...