这个int在C中浮动转换有什么问题?

时间:2014-01-27 15:10:19

标签: c floating-point integer type-conversion

我对以下代码的输出感到困惑:

float a  = 1.32;
int* b;
b= &a;
printf("%d", *b);

这段代码将float转换为int,但我得到的输出是:1068037571

这是否与计算机的IEEE 754转换功能有关? 谢谢!

3 个答案:

答案 0 :(得分:10)

您的程序调用未定义的行为。您只需将float的表示重新解释为int。您绝对不会将int转换为float。你不能指望任何特定的行为。

要将float转换为int,您可以使用如下代码:

int b = a;

float截断为int

答案 1 :(得分:5)

您在使用代码时正在查看浮点数的存储方式。浮点在内存中占用4个字节(通常),如下所示(维基百科中的示例):

enter image description here

运行代码时,假装这些位是四字节整数:

float a  = 1.32;
int* b;
b= &a;
printf("%d", *b);

如果要查看十六进制表示,只需执行

printf("%08x", *b);

你会得到

3f9d70a4

意味着位模式是

00111111100111010111000010100100

打破它:

0 01111111 00111010111000010100100

签署位0 指数01111111 分数(1)00111010111000010100100

你会发现二进制数

100111010111000010100100 = 10317988

那个

10317988.0 / (4096.0*2048.0) = 1.23

更新完整程序,准确显示如何执行此操作:

#include <stdio.h>
#include <math.h>
#include <stdint.h>

int main(void) {
  float a = 1.23;
  uint32_t *b = (uint32_t *)&a;

  uint32_t signbit;
  uint32_t exponent;
  uint32_t mantissa;
  uint32_t fpAsInt;

  fpAsInt = *b;

  signbit = (fpAsInt & 0x80000000) >> 31;
  exponent = (fpAsInt & 0x7F800000) >> 23 ;
  mantissa = (fpAsInt & 0x007FFFFF) | 0x00800000;
  printf("fpAsInt: 0x%08x\n", fpAsInt);
  printf("sign bit: %d\n", signbit);
  printf("exponent: 0x%02x\n",  exponent);
  printf("mantissa: 0x%03x\n",  mantissa);
  printf("the value is %10f\n", ((signbit == 1)?-1.0:1.0)*mantissa / pow(2.0, (127 - exponent + 23)));
  printf("the original value was %10f\n", a);
}

打印结果

fpAsInt: 0x3f9d70a4
sign bit: 0
exponent: 0x7f
mantissa: 0x9d70a4
the value is 1.2300000191
the original value is 1.2300000191

我在最后一行使用浮点数学似乎是作弊 - 有效的批评,但这里的重点是展示如何构造浮点,而不是如何使用整数数学来提取值。

注 - 我假设浮点数是IEEE 4字节表示。此外,我包括一些特定的转换来摆脱编译器警告。只有当你确定你知道自己在做什么时才这样做......

ONE MORE EDIT

有人指出代码仍然存在未定义的行为。为了解决这个问题,并且仍然让您对上述内容有所了解,让我们再来一次。现在我使用一个位数组和一个浮点数的联合来“合法地”访问不同的元素 - 并且在使用-Wall -pedantic进行编译时没有得到任何警告。这可能还不够,但这是我所知道的最好的......

#include <stdio.h>
#include <math.h>
#include <stdint.h>

union ieee754_float
  {
    float f;

    /* This is the IEEE 754 single-precision format on a little-endian machine.  */
    struct
      {
        unsigned int mantissa:23;
        unsigned int exponent:8;
        unsigned int negative:1;
      } ieee;
    };

int main(void) {
  float a = 1.23;
  union ieee754_float *pa;
  pa = (union ieee754_float*)&a;

  uint32_t signbit;
  uint32_t exponent;
  uint32_t mantissa;

  signbit = pa->ieee.negative;
  exponent = pa->ieee.exponent;
  mantissa = pa->ieee.mantissa | 0x00800000;
  printf("sign bit: %d\n", signbit);
  printf("exponent: 0x%02x\n",  exponent);
  printf("mantissa: 0x%03x\n",  mantissa);
  printf("the value is %.10f\n", ((signbit == 1)?-1.0:1.0)*mantissa / pow(2.0, (127 - exponent + 23)));
  printf("the original value is %.10f\n", a);
}

答案 2 :(得分:2)

回到这些基本规则可以回答StackOverflow上C标签中的许多问题:

  • &获取变量并生成指针
  • *获取指针并生成变量

所以你说“接受这个浮点变量并让我成为一个指针。现在接受那个指针,让我成为一个int变量。”你从来没有说过“取这个漂浮值并让我成为一个int值”。你说“把一个可以变成浮点变量的指针转而变成一个int变量”。当你这样做时会发生什么?这完全取决于编译器的决定。