c++ 可变参数 默认类型升提升 可变参数陷阱

 使用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的情况下的定义
c++ 可变参数 默认类型升提升 可变参数陷阱_第1张图片
_INTSIZEOF(n) 作用是将字节数不是sizeof(int)整数倍的类型占用空间改为sizeof(int)的整数倍。所以va_arg对于char,short等实际处理时都是当作int来处理。所以数据在作为不定参数传递到fun函数中时,已经被编译器做过了数据类型提升处理。及char、short,int变成了int,float 变成了double。

对于vprintf,第二个参数的数据类型要求比较严格。如果希望解析成功,数据类型必须是由int 和double等类型来组装的数据。

 

 

 

 

你可能感兴趣的:(c++)