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

标签 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(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 版。

最佳答案

不,不应该。使用 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,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 011.0 在内部看起来像 00 00 00 00 00 00 f0 3f(都在小端机器上)。

将诸如 00 00 00 01 00 00 00 02 之类的堆栈内容解释为 double 会导致奇怪的结果。

关于c - 具有可变参数的函数 - 奇怪的输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19605284/

相关文章:

c - 成功写入不会在文件上写入任何内容

c - 从不兼容的指针类型传递参数 x ...

c - 关于使用 Mac 终端链接文件

c++ - linux上的gcc使用哪个线程库来实现OpenMP?

c - 使用 zlib 解压 PNG

go - 在 golang 中存储和传递可变参数?

c++ - 在 Debug模式下运行时缓冲区溢出

scala - 将单个参数和 Seq 传递给 var-arg 函数

c - 从树的每个节点添加整数

linux - 交叉编译编译器何时有意义?