参考文档: http://bbs.csdn.net/topics/70288067(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 转载请标明来源 )本文的二个重点:1. 可变参数实际上通过首个参数的地址来获取其它参数的地址因为是顺序存储传过来的2. 可变参数为了处理方便所有的浮点型都是按照double型压栈因此像printf采用的可变参数它只需要使用%f显示double型不需要管float型。关注printf的精度需要先关注printf的实现关于printf的实现我们就要关注一下可变参数的实现:变参的一个例了:voidtestIntAndFloat(inttype, ...){va_listargptr;va_start(argptr,type);if(type 0 ){intnva_arg(argptr,int);printf(%d\n,n);}elseif(type 1){doubledva_arg(argptr,double); // 必须使用double接收后边会说明原因printf(%f\n,d);}else{}}测试:floatf1 12345;testIntAndFloat(0,123);testIntAndFloat(1,f1,f1);输出:12312345.0000查看变参相关的定义:typedefchar*va_list;#defineva_start(ap,v) (ap (va_list)_ADDRESSOF(v) _INTSIZEOF(v) )#define_ADDRESSOF(v) ( reinterpret_castconstchar(v))#define_INTSIZEOF(n) ( (sizeof(n) sizeof(int) - 1) ~(sizeof(int)- 1) )#defineva_arg(ap,t) ( *(t*)((ap_INTSIZEOF(t)) -_INTSIZEOF(t)) )//_ADDRESSOF(v):获取v的地址并转为char*型//_INTSIZEOF(n):实现4字节对齐//va_start(ap,v): 获取参数v之后的地址//va_arg(av, t): ap地址向后移t类型size并返回ap地址之前t类型变量的值看一个输出%d的例子:__int64i 123456;printf(%d,%d \n,i,i);结果为: 123456, 0printf(%d,%d,%d,%d \n,i,i);结果为: 123456,0,123456,0printf(%lld,%lld \n,i,i);结果为: 123456, 123456从上面的内容可以看出来:%d时每次读取的位数是4位而int64有8位所以如果使用%d的话分两次读取完。(由于是little endian先读低位再读高位先读到123456再读到0)再看输出%f的例子floatf 123456789123456789.0;double fd f;doubled 123456789123456789.0;printf(%f\%f\n%f\n,f,fd,d);结果为:1234567939550609400.00001234567939550609400.00001234567890123456800.0000可以看出:float实际是被转成double型存储显示的float的精底通常是6-7位double是15-16位printf的时候显示的位数是按double算的。再看这个例子运行时观察内存信息(观察内存方式: VC-调试-窗口-内存)voidtestArgs(inttype, ...){va_listargptr;va_start(argptr,type);for(inti0;i8;i){int*pNumber (int*)argptr;float*pFloat (float*)argptr;va_arg(argptr,int);printf((\naddrss:%d int value: %d float value: %f),pNumber, *pNumber, *pFloat);}}voidTestFuncArgs(intn1 31,floatf131.0,doubled131.0,charc131,boolb131,shorts131,__int64n231,intn331){printf(\nf1%f,f1);printf((\naddrss of arg(int): %x, value: %d), n1,n1);printf((\naddrss of arg(float): %x, value: %d|%d, float:%f), f1,f1,f1);printf((\naddrss of arg(double): %x, value: %d|%d, float:%f), d1,d1,d1);printf((\naddrss of arg(char): %x, value: %d), c1,c1);printf((\naddrss of arg(bool): %x, value: %d), b1,b1);printf((\naddrss of arg(short): %x, value: %d), s1,s1);printf((\naddrss of arg(__int64): %x, value: %d), n2,n2);printf((\naddrss of arg(int): %x, value: %d), n3,n3);testArgs(n1,f1,d1,c1,b1,s1,n2,n3);}当按函数定参参数形式传递TestFuncArgs时:Int/char/bool/short占用4字节Float占用4字节Double点用8字节__int64占用8字节内存中连续显示1f 00 00 00 --int00 00 f8 41 --float00 00 00 00 00 00 3f 40 --double1f 00 00 00 --char01 00 00 00 --bool1f 00 00 00 --short1f 00 00 00 00 00 00 00 –int641f 00 00 00 00 00 -- int当采用不定参数传递testArgs时:其它均不变但float为8字节存储这个是需要非常注意的一个事情。使用%d打印时只会取4字节需要使用两个%d%d才能打印一个float。内存中连续显示1f00 00 00 -- int00 00 00 00 00 00 3f 40 --float00 00 00 00 00 00 3f 40 --double1f 00 00 00 --char0100 00 00 --bool1f 00 00 00 --short1f 00 00 00 00 00 00 00 –int641f 00 00 00--int(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 转载请标明来源)