C 具有可变参数的函数--奇怪的输出

C 具有可变参数的函数--奇怪的输出,c,gcc,variadic-functions,C,Gcc,Variadic Functions,我已经写了一个包含变量参数的小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(a

我已经写了一个包含变量参数的小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));
}
只有
calculateAverage(4,2.0,4.0,6.0,8.0)
给出了预期的输出,即当我用小数点专门表示它们时

  • va_arg(argumentList,double)
    是否应该安全地将数字提升为双倍

  • calculateAverage(3,1,2,3)
    如何在两个不同的地方给出两个结果?我是否在某种“未定义的行为”领域内?如果是,如何进行


我使用的是gcc版本4.8.1

问题在于该语句
sum+=va_arg(argumentList,double)

由于您试图解释为
double
,因此
整数文本将出现问题。将您的
int
s转换为
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
无法确定传递给函数的参数的实际类型,但使用作为类型宏参数传递的任何类型作为其类型

不,不应该。使用
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 =  &num;
  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.0,2.0,3.0));
给予

因为整数
1
内部看起来像
00 01
,而
1.0
内部看起来像
00 f0 3f
(两者都在小型endian机器上)


将堆栈内容(如
00 00 00 01 00 00 02
解释为双精度将导致奇怪的结果。

变量参数函数的参数提升遵循正常规则:小于
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);

解决方案是确保您正在传递双参数,或者使用不同类型的参数,例如格式字符串。(就像
printf
中的一个一样)

或者,您可以只在数字上添加小数位以提高可读性,而不必进行大量的类型转换。e、 g.3->3。0@PatTeen-那将是短暂而甜蜜的,是的。
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
 va_arg(argumentList,double)
calculateAverage(4,2.0f,4.0f,6.0f,8.0f);