【问题标题】:Why does my function print '0'?为什么我的函数打印'0'?
【发布时间】:2014-08-18 09:12:19
【问题描述】:

这是我的代码,我不知道为什么会这样:

#include <stdio.h>

void foo(float *);

int main()
{
    int i = 10, *p = &i;
    foo(&i);
}

void foo(float *p)
{
    printf("%f\n", *p);
}

输出:

0

【问题讨论】:

  • 您正在尝试将int* 转换为float*。你的编译器应该会出错(至少在标准 C++ 中)。
  • 因为您忽略了告诉您int* 不是float* 的编译器警告
  • 您的程序打印 0。与下面告诉您程序错误原因的所有答案相反,您的程序可能正在运行。也就是说,就像您以较少争议的方式完成类型双关一样工作。问题是,您期望什么以及是什么让您认为“0”不是通过%f 对与10 具有相同位的浮点数的正确转换?

标签: c++ c floating-point int format-specifiers


【解决方案1】:

正如已经说过的,您将整数变量的地址作为单精度浮点数的地址传递。

理想情况下,应该禁止这种隐式转换,但取决于编译器以及它是干净的 C 还是 C++,它可能只会导致警告。

但为什么它打印的正好是 0?

这是因为单精度FPN的方式是represented in memory

(1 bit of sign)|(8 bits of biased exponent)|(23 bits of significand(mantissa))

二进制的10是

0|0000 0000|000 0000 0000 0000 0000 0000 1010

所以,当解释为浮点值时:

(sign = 0)(biased exponent = 0)(significand = 10)

有偏指数是正常指数加上 127 - http://en.wikipedia.org/wiki/Exponent_bias

要计算该值,我们将使用以下公式:

floatValue = ((sign) ? (-1) : (1)) * pow(2, normalExponent) * significand

这将产生:

floatValue = 1 * pow (2, 0 - 127) * 10 = 10 * 2 in pow -127.

这是一个非常小的数字,当使用%f 说明符表示时,它会变成"0" 字符串。

解决方案:

要解决这个问题,只需在调用 foo 之前使用临时变量和显式转换:

int main()
{
    int i = 10;

    float temp = (float)i;

    foo(&temp);
}

void foo(float *p)
{
    printf("%f\n", *p);
}

P.S.为避免将来出现此类问题,请始终将编译器设置为最大现实级别的警告,并始终在运行应用程序之前处理每个警告。

【讨论】:

  • 其实有偏差的指数值0对应2^-126,理解为浮点数是次正规的。 en.wikipedia.org/wiki/…
  • 为什么偏差为 126?我以为是 127。
【解决方案2】:

因为您将整数对象和指针对象声明为intint * 而不是floatfloat *

您不能将 int * 类型的对象传递给需要 float * 类型参数的函数,而无需显式转换。

变化:

  int i = 10, *p = &i;

  float i = 10, *p = &i;

请注意,main 中的 p 指针未使用,可以删除其声明。

【讨论】:

    【解决方案3】:

    您实际上是将指向 int 的指针转换为指向 float 的指针。这是合法的,但不好 - printf 试图将为 int 保留的内存理解为浮点数(在内存中的表示方式不同),结果未定义。

    【讨论】:

      【解决方案4】:

      您尝试读取分配给 int 类型变量的区域并尝试读取为浮点数。

      浮点数写为尾数和指数。根据内存中的表示,很可能你正在用你的“10”加载指数,而尾数保持为零。结果,0^10(或无论如何解释)为 0。

      【讨论】:

      • 真棒......可爱的解释@SF
      • 不,在几乎所有体系结构中,浮点表示具有与整数相同的字节顺序(这样做有充分的理由),因此数字 10 中的位最终为低-有效数字的权重位。最终结果是第 10 个正次正规数,这个数字非常小,以至于 %f 将其表示为“0”(但 %e 没有)。
      【解决方案5】:

      这是因为,您将 Integer 传递给函数,而您正在使用 float 数据类型。

      编译时-如果启用警告标志,您将收到警告-

      root@sathish1:~/My Docs/Programs# cc float1.c
      float1.c: In function ‘main’:
      float1.c:11:5: warning: passing argument 1 of ‘foo’ from incompatible pointer type [enabled by default]
      float1.c:3:6: note: expected ‘float *’ but argument is of type ‘int *’
      

      它清楚地告诉你你在做什么。

      你的函数除了float *,但是你传递了int *。所以打印的时候会搜索相应的内存区域并尝试打印。但是浮点变量存储在 IEEE 754 标准中,但该函数接收整数地址,因此它将尝试打印该内存位置中的数据(int 不存储在 IEEE 754 std 中)。所以结果是未定义的。

      【讨论】:

        【解决方案6】:

        您正在调用函数,期望 float* 带有指向 int 的指针。在 C++ 中,这是一个错误,您的代码无法编译。在 C 中,您很可能会收到警告和未定义的行为。

        【讨论】:

          猜你喜欢
          • 2021-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-25
          • 2021-08-06
          相关资源
          最近更新 更多