1定义
这些宏在stdarg.h,定义如下:
1 #include <stdarg.h> 2 typedef char *va_list; 3 #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 4 #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址 5 #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数的值 6 #define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效 7 8 void va_start(va_list ap, last); 9 type va_arg(va_list ap, type); 10 void va_end(va_list ap); 11 void va_copy(va_list dest, va_list src);
以上几个宏定义关键是_INTSIZEOF(n)的含义。
2 #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
含义是向上取整成 sizeof(int) 的整数倍,用来地址对齐。
1) 数学整除的例子
举个简单的数学整除运算例子
如5/2=2, 7/2=3,再进行如下运算:
(5/2)*2=4, (7/2)*3=6
即可得到小于被除数的最大的除数的整数倍。
2)字节对齐的含义:
现在有以数据长度为L = 4M+m,如果按照M字节对齐, 对齐后需占用5个M,但实际长度记为4M+m。
如上,蓝色一个格为M字节,红色为m字节,m < M。
经过上述数学整除运算后L变成4M = (L/M) * M。
但是与所需的5M 少了一个M。那怎么办呢?
如果将原数据长度增加一格(L+M),再进行上述运算,即((L+M)/M) * M = 5M
3)但是呢,会存在如下的问题
假设数据长度为Y = 6M,刚好为一格长度M的整数倍。
经过以上运算为:((Y+M)/M) * M = 7M,那如果不加M ,只加M-1呢?
((Y+M-1)/M) * M = 6M,对头,这样就完美了。
4)言归正传,解释宏定义。
(sizeof(n)+sizeof(int)-1) & (~(sizeof(int) - 1)) = _INTSIZEOF(n)
((Y+M-1) /M) * M = 6M
&符号左边部分相当于(Y+M-1),右边&~(sizeof(int) - 1),对应/M*M。对二进制来说就是右移M位,再左移M位。因为右移会丢掉低位的,再次左移后相当于把低位清零了。
若a为2的n次幂,那就是最高位为1,其余位即低位为n个0。
a-1的二进制相反,低位n个1,最高位为0。再按位取反就是a,即(~(sizeof(int) - 1))。
最后再按位与,就可以实现将A的低n位清零,即&(~(sizeof(int) - 1))。
3 函数堆栈中的摆放
在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码 ,堆栈地址不断递减。最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.参数在堆栈中的分布情况如下:
“
最后一个参数
倒数第二个参数
...
第一个参数
函数返回地址
函数代码段
”
void va_copy(va_list dest, va_list src);很简单,src copy到 dest,不在详述。
4实例
1)int型实例:
1 #include <stdio.h> 2 #include <stdarg.h> 3 //int demo(int format, ...); 4 int demo(int format, ...) 5 { 6 va_list ap; 7 int n; 8 va_start(ap, format); 9 while(n != 0{ 10 n = va_arg(list, int); 11 // if(n != 0){ 12 printf("%d ",n); 13 // break; 14 // } 15 printf("para #%d is:%d ",sum,n); 16 } 17 va_end(ap); 18 return 0; 19 } 20 void main() 21 { 22 demo(1,2,3,4,5,6,7,8,9,0); 23 }
编译执行结果:
./test
para #0 is : 2
para #0 is : 3
para #0 is : 4
para #0 is : 5
para #0 is : 6
para #0 is : 7
para #0 is : 8
para #0 is : 9
para #0 is : 0
2)char型实例:
1 #include <stdio.h> 2 #include <stdarg.h> 3 //int demo(int format, ...); 4 void demo(char *format, ...) 5 { 6 va_list list; 7 va_start(list,format); 8 char *ch; 9 while(ch != ""){ 10 ch = va_arg(list, char *); 11 //if(strcmp(ch,"") == 0){ 12 printf("%s ",ch); 1314 //} 15 printf("%s ",ch); 16 } 17 va_end(list); 18 } 19 int main() 20 { 21 demo ("test","this","is","a","test",""); 22 return 0; 23 }
编译执行结果:
./test
para #0 is : this
para #0 is : is
para #0 is : a
para #0 is : test
para #0 is :
3)vsprintf ,vsnprintf的使用实例
1 #include <stdio.h> 2 #include <stdarg.h> 3 char buffer1[80] 4 char buffer2[80]; 5 int demo (char *format, ...) 6 { 7 va_list ap; 8 va_start(ap, format); 9 vsfprintf(buffer1, format,ap); 10 vsnprintf(buffer2, 17,format, ap); 11 va_end(ap); 12 printf("vsprintf:%s ",buffer1); 13 printf("vsnprintf:%s ",buffer2); 14 return 0; 15 } 16 int main() 17 { 18 int num = 30; 19 float flat = 90.000000; 20 char c_data [4]= "abc"; 21 demo ("%d %f %s",num,flat,c_data); 22 printf("sizeof(int):%d,sizeof(float):%d,sizeof(string):%d ",sizeof(int),sizeof(float),sizeof(string)); 23 return 0; 24 }
sizeof(int):4,sizeof(float):4,sizeof(string):4
vsprintf :30 90.000000 abc
vsnprintf:30 90.000000 abc