我编写了一个涉及变量参数的小型C程序。见下文: -
#include <stdio.h>
#include <stdarg.h>
double calculateAverage(int num,...)
{
va_list argumentList;
double sum=0;
int i;
va_start(argumentList,num);
for(i = 0; i < num; i++)
{
sum += va_arg(argumentList,double);
}
va_end(argumentList);
return(sum/num);
}
int main()
{
printf("%f\n",calculateAverage(3,1,2,3));
printf("%f\n",calculateAverage(4,2,4,6,8));
printf("%f\n",calculateAverage(4,2.0,4.0,6.0,8.0));
printf("%f\n",calculateAverage(3,1,2,3));
}
输出是:
0.000000
0.000000
5.000000
5.333333
只有calculateAverage(4,2.0,4.0,6.0,8.0)
给出预期输出,即当我用小数点专门表示它们时。
va_arg(argumentList,double)
不应该安全地将数字提升一倍吗?
calculateAverage(3,1,2,3)
如何在2个不同的地方提供2个结果?我在一些“未定义的行为”范围内吗?如果是,怎么做?
我正在使用gcc版本4.8.1。
答案 0 :(得分:2)
问题在于此声明sum += va_arg(argumentList,double);
由于您尝试将其解释为double
- Integer literals
会出现问题。将int
转换为double
,它应该可以正常工作。
printf("%f\n",calculateAverage(3,(double)1,(double)2,(double)3));
printf("%f\n",calculateAverage(4,(double)2,(double)4,(double)6,(double)8));
printf("%f\n",calculateAverage(4,2.0,4.0,6.0,8.0));
printf("%f\n",calculateAverage(3,(double)1,(double)2,(double)3));
va_arg
无法确定传递给函数的参数的实际类型,但使用作为类型宏参数传递的任何类型作为其类型。
答案 1 :(得分:2)
不,不应该。使用va_arg()
,您可以告诉我们应该假设数据的格式。关于内部表示,1.0
看起来与1
完全不同。如果您将1
作为double
,则会出现完全错误。
以下是运行函数调用时堆栈上发生的事情:
double calculateAverage(int num,...)
{
va_list argumentList;
double sum=0;
int i;
va_start(argumentList,num);
printf("%p", &num);
unsigned char * c = #
for(i = 0; i < num * sizeof(double) + 4; i++, c++)
{
printf(" %02x", *c);
}
printf("\n");
for(i = 0; i < num; i++)
{
sum += va_arg(argumentList,double);
}
va_end(argumentList);
return(sum/num);
}
然后,
printf("%f\n",calculateAverage(3,1,2,3));
给出
0xbfc507d0 03 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 ...
-0.054776
,而
printf("%f\n",calculateAverage(3,1.0,2.0,3.0));
给出
0xbfd15290 03 00 00 00 00 00 00 00 00 00 f0 3f 00 00 00 00 00 00 00 40 00 00 00 00 00 00 08 40
2.000000
因为整数1
内部看起来像00 00 00 01
,而1.0
内部看起来像00 00 00 00 00 00 f0 3f
(两者都在小端机器上)。
将诸如00 00 00 01 00 00 00 02
之类的堆栈内容解释为double会导致奇怪的结果。
答案 2 :(得分:2)
变量参数函数的参数提升遵循常规规则:小于int
(char
,short
等)的类型被提升为int
; float
被提升为double
,但int
不会被提升为double
,所以
va_arg(argumentList,double)
告诉编译器参数类型为double
,但在某些调用中它们不是。{请注意,您可以传递float
,因为它们会被提升为double
。
calculateAverage(4,2.0f,4.0f,6.0f,8.0f);
解决方案要么确保传递double
个参数,要么使用其他类型的parmN
,例如格式字符串。 (就像printf
)