函数的代码是在编译时候生成的,对于带有不定参数个数(甚至对于每一个参数对应的类型也不也一样)的函数,编译器怎么在支持这样的函数。
1 #include < stdio.h>
2 #include < string.h>
3 #include < stdarg.h>
4
6 int t(...)
7 {
8 return 0;
9 }
10 /* 函数原型声明,至少需要一个确定的参数,注意括号内的省略号 */
11 int demo( char *, ...) ;
12
13
14 void main( void )
15
16 {
17 demo("DEMO"," This"," is "," a ","demo!", "\0");
18 }
19
20 int demo( char *msg, ... )
21 {
22 va_list argp; /* 定义保存函数参数的结构 */
23 int argno = 0; /* 纪录参数个数 */
24 char *para; /* 存放取出的字符串参数 */
25
26 va_start( argp, msg );
27 while (1)
28 {
29 para = va_arg( argp, char *);
30 if ( strcmp( para, "\0" ) == 0 ) /* 采用空串指示参数输入结束 */
31 break;
32
33 printf("参数 #%d 是: %s\n", argno, para);
34 argno++;
35 }
36 va_end( argp ); /* 将argp置为NULL */
37
38 return 0;
39 }
有意思是介绍几个宏
先看这个:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
这个是为了内存对齐,可以将n这个类型长度转换为sizeof(int)的倍数长度。 比如sizeof (n)=9 ,sizeof(int)=4,
那么 _INTSIZEOF(n) = ( 9 + 4 -1)&~(4 -1) = 12/3 = 4. 也就是将 9 转换为 12,为边界对齐加了一个3.
关一个这个的证明在这:
蛮经典的:http://blogold.chinaunix.net/u/1129/showart_397677.html
//#define va_start _crt_va_start
//#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
//#define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )
//#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
//#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
NOTE:
1.从va_start宏依赖第一个函数地址,得到下一个函数的地址。这也就是为什么不定参数的函数需要至少一个参数。
2.对于函数参数的个数的判读,需要自己。如果printf里面第一个参数定义可以得到后面的参数个数,或者最后一个参数要有定义。