使用vs版本vs2015 64bit win10.
#include "stdarg.h"
using namespace std;
#pragma pack(1)
struct St
{
int a;
double b;
float c;
char d;
unsigned short e;
short f;
int z;
};
#pragma pack()
void fun(int i, ...);
int main(int argc, char *argv[])
{
double value = 10.1234567891;
St t;
t.a = 10;
t.b = value;
t.c = 10.2f;
t.d = 'a';
t.e = 1232;
t.f = 342;
t.z = 11;
printf("%p,%p,%p,%p,%p,%p,%p\n", &t.a, &t.b, &t.c, &t.d,&t.e,&t.f,&t.z);
fun(4, t.a, t.b, t.c, t.d,t.e,t.f,t.z);
char *y = (char*)&t;
printf("%d\n", sizeof(St));
printf("%d,%.10f,%f,%c,%d,%d,%d;\n", t.a, t.b, t.c,t.d,t.e,t.f, t.z);
vprintf("%d,%.10f,%f,%c,%d,%d,%d;\n", y);//输出错误,y原始的数据不能含有char,short等类型
return 0;
}
void fun(int i, ...)
{
va_list li;
va_start(li,i);
vprintf("%d,%.10f,%f,%c,%d,%d,%d;\n", li);
St t;
//St t = *((St*)li);
//printf("%d,%.10f,%f,%c;\n", t.a, t.b, t.c, t.z);
t.a = va_arg(li, int);
t.b = va_arg(li, double);
//t.c = va_arg(li, float);
t.c = va_arg(li, double);
t.d = va_arg(li, char);
t.e = va_arg(li, unsigned short);//
t.f = va_arg(li, short);
t.z = va_arg(li, int);
printf("%p,%p,%p,%p,%p,%p,%p\n", &t.a, &t.b, &t.c,&t.d, &t.z);
va_end(li);
printf("%d,%.10f,%f,%c,%d,%d,%d;\n", t.a, t.b, t.c, t.d, t.e,t.f,t.z);
}
如上为vs中的测试代码。
可变参数传递在传递过程中有一个“默认实际参数提升”(参考https://blog.csdn.net/jchnlau/article/details/9466435)的过程
在函数fun中,不定参数中的第3个本来是传递float,但是在这里如果设置解析成float却导致第三个及第三个参数后的所有参数解析都是错误的,如果将第三个参数改为double类型来解析,发现后面的能全部解析正确。
可以参看 "stdarg.h" 中的宏va_start 和va_arg,va_end在x86的情况下的定义
_INTSIZEOF(n) 作用是将字节数不是sizeof(int)整数倍的类型占用空间改为sizeof(int)的整数倍。所以va_arg对于char,short等实际处理时都是当作int来处理。所以数据在作为不定参数传递到fun函数中时,已经被编译器做过了数据类型提升处理。及char、short,int变成了int,float 变成了double。
对于vprintf,第二个参数的数据类型要求比较严格。如果希望解析成功,数据类型必须是由int 和double等类型来组装的数据。