重新解释从float到int的转换

时间:2019-04-04 08:17:03

标签: c++

float f = 12.5;
unsigned int _f = *reinterpret_cast<int*>(&f);
std::cout << _f << std::endl; // result: 1095237632

有人可以解释一下这种转换的工作方式吗? _f代表什么?

编辑 因此在转换为二进制后我得到的这个数字10952376320b1000001010010000000000000000000,而在IEEE-754中这个二进制数字是12.5。我正确吗?

3 个答案:

答案 0 :(得分:6)

没人能解释(*),因为它不起作用。

来自cppreference

  

与static_cast不同,但与const_cast不同,reinterpret_cast   表达式不能编译为任何CPU指令(除非   在整数和指针之间或在晦涩的体系结构上进行转换   指针表示取决于其类型)。纯粹是   编译时指令,指示编译器处理   表达式,就好像其类型为new_type。

     

只能通过reinterpret_cast进行以下转换,   除非这种转换会消除稳定性或波动性。

然后遵循一系列规则,涵盖允许重新解释强制类型转换的内容。将类型A转换为完全不相关的类型B不在其中,并且您的代码表现出不确定的行为。

(*)严格来说是不正确的。您将float视为一个int,如果您查看它们在硬件上的表示形式,并且检查编译器的输出,则可以弄清楚为什么得到值,尽管未定义行为是未定义的,因此不值得输入详细信息除非您愿意编写不可移植的代码。

答案 1 :(得分:4)

让我们看一下两个功能。其中之一强制转换为定期将其转换为int,其中之一使用reinterpret_cast重新解释其强制转换:

int cast_to_int(float f) {
    // Rounds f to an int, rounding towards 0
    return (int)f; 
}
int reinterpret_cast_to_int(float i) {
    // Just copies the bits
    return *reinterpret_cast<int*>(&i); 
}

那么实际发生了什么?让我们看一下程序集:

cast_to_int(float):
    cvttss2si       eax, xmm0   // We cast to an int
    ret
reinterpret_cast_to_int(float):
    movd    eax, xmm0           // We directly copy the bits
    ret

在第一种情况下,有一条汇编指令执行转换:

cast_to_int(0.7) -> 0
cast_to_int(1.0) -> 1
cast_to_int(1.5) -> 1
cast_to_int(2.1) -> 2

在第二种情况下,reinterpret_cast只是直接转换位的基础表示形式。它实际上并没有执行任何操作,该函数只是将输入寄存器复制到输出寄存器。

在幕后,float的位表示形式与int截然不同,这就是为什么您得到奇怪的数字的原因。

答案 2 :(得分:-4)

如下注释所示,对于不相关的类型,使用reinterpret_cast ist不安全。因此,请勿以这种方式使用它。

首先,应避免将int分配给uint。

对于x86 / x64系统,float通常表示为4个字节,例如uint32_t,并且它们的对齐方式基本上相同。

许多编译器允许以下操作:     uint32_t _f = * reinterpret_cast(&f);

但是由于某些原因,这会导致不确定的行为(感谢评论): -优化 -对齐 -...

使用memcpy代替。

如果对齐方式相同并且值存储在内存中,则以下效果描述了使用reinterpret_cast时发生的情况:

4个字节浮点数的存储位置为&f。通过将重新解释转换为uint32_t,此内存将重新解释为uint32。取消引用的值_f包含与浮点f相同的字节,但解释为uint32。 您可以将其还原并获得原始值12.5:

float f = 12.5;
uint32_t _f = *reinterpret_cast<uint32_t*>(&f);
float _fnew = *reinterpret_cast<float*>(&_f);
std::cout << _fnew << std::endl; // result: 12.5

reinterpret_cast仅重新解释存储位置(地址)。 如果对齐方式不相同,或者将值存储在寄存器中,进行了优化等等,则强制转换会导致未定义的值。