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

mac*_*aca 2 c floating-point integer type-conversion

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

float a  = 1.32;
int* b;
b= &a;
printf("%d", *b);
Run Code Online (Sandbox Code Playgroud)

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

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

Dav*_*nan 10

您的程序调用未定义的行为.你只是重新解释了float作为一个的表示int.你绝对不会将inta 转换为a float.你不能指望任何特定的行为.

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

int b = a;
Run Code Online (Sandbox Code Playgroud)

截断float到一个int.

  • @macalaca:如果你的教授声明`*b`在显示的代码之后有意义,那么你的教授要么错了,要么指的是保证这种非标准行为的特定C实现.检查编码float`a`的字节的正确方法是将其表示的字节复制到另一个对象中,例如`unsigned int b; memcpy(&b,&a,sizeof b);`,或者使用union,例如`unsigned int b =(union {float f; unsigned int u;}){a} .u;`.这两个都需要`sizeof(float)== sizeof(unsigned int)`. (4认同)

Flo*_*ris 5

您正在使用代码执行的操作是查看浮点数的存储方式.浮点占用内存中的4个字节(通常),如下所示(来自维基百科的例子):

在此输入图像描述

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

float a  = 1.32;
int* b;
b= &a;
printf("%d", *b);
Run Code Online (Sandbox Code Playgroud)

如果你想看到十六进制表示,那就做

printf("%08x", *b);
Run Code Online (Sandbox Code Playgroud)

你会得到的

3f9d70a4
Run Code Online (Sandbox Code Playgroud)

意思是位模式是

00111111100111010111000010100100
Run Code Online (Sandbox Code Playgroud)

打破它:

0 01111111 00111010111000010100100
Run Code Online (Sandbox Code Playgroud)

符号位0 指数01111111 分数(1)00111010111000010100100

你会发现那个二进制数

100111010111000010100100 = 10317988
Run Code Online (Sandbox Code Playgroud)

然后

10317988.0 / (4096.0*2048.0) = 1.23
Run Code Online (Sandbox Code Playgroud)

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

#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);
}
Run Code Online (Sandbox Code Playgroud)

打印结果

fpAsInt: 0x3f9d70a4
sign bit: 0
exponent: 0x7f
mantissa: 0x9d70a4
the value is 1.2300000191
the original value is 1.2300000191
Run Code Online (Sandbox Code Playgroud)

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

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

一个编辑

有人指出代码仍然存在未定义的行为.为了解决这个问题,并且仍然让您对上述内容有所了解,让我们再来一次.现在我使用一个位数组和一个浮点数的联合来"合法地"访问不同的元素 - 并且在编译时没有得到警告-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);
}
Run Code Online (Sandbox Code Playgroud)