c++ 当指向32位整数的指针被强制转换为指向浮点数的指针并解除引用时会发生什么?

2eafrhcq  于 2022-12-20  发布在  其他
关注(0)|答案(3)|浏览(123)

我看过这个演员阵容:

const std::uint32_t tmp = (some number);
float ToFloat = *(float*)(&tmp);

但是在强制转换的时候,错误的数字进入了浮点数。而且,如果我使用静态强制转换,那么它是正确的。
1.为什么会这样呢?

  1. static_cast究竟是如何工作的?
  2. *(float*)(&Tmp)意味着我们试图解引用指向浮点数的指针,该指针位于地址&tmp,对吗?
cczfrluj

cczfrluj1#

为什么会这样呢?
程序有未定义的行为,因为你通过float的眼睛从int读取。这在C++中是不允许的。
static_cast究竟是如何工作的?
在本例中,它执行与float ToFloat = Tmp;相同的转换,即,将int转换为float并将其赋值给ToFloat
*(float*)(&Tmp)意味着我们试图解引用指向浮点数的指针,该指针位于地址& Tmp处,对吗?
&Tmp处没有float,只有int。然而,您告诉编译器指针指向float并解引用该指针。int s和float s的位模式非常不同,因此不仅它具有未定义的行为,而且您将很难得到正确的结果。

bjp0bcyl

bjp0bcyl2#

存储整数

整数以二进制(基数为2)表示形式存储。int32_t占用32位。

储存彩车

在大多数的C++编译器中,使用一个叫做IEEE754的标准来存储浮点数和双精度数,这与整数的存储方式有很大的不同。
您可以使用某种IEEE-754 Floating Point Converter检查数字是如何存储的。

示例

让我们考虑数字5的一个简单例子。

const uint Tmp = 5;

Tmp将作为0x00000005存储在存储器中,因此&Tmp将指向相同的值。

float ToFloat = *(float*)(&Tmp);

将其转换为浮点指针会将0x00000005视为IEEE 754格式,其值为7.00649232162e-45

静态转换

静态强制转换使用安全隐式转换在兼容类型之间执行转换。
请注意,您的问题是将int*转换为float*,这不是一个安全的转换。您可以安全地将int转换为float

const uint32_t Tmp = 5;
float ToFloat = (float)Tmp; // 5

更多关于static_cast conversion的信息。

kx7yvsdv

kx7yvsdv3#

这段代码尝试将浮点数的32位表示形式转换为实际的浮点值。(大多数情况下)形式的数的表示(−1)s × m × 2e。对于给定的浮点格式,机器字中的一定数量的位被分配给每个 s(符号位),m(尾数或有效位)和 e 可在位表示内直接操纵那些位以便构造任何可能的浮点值,从而绕过由语言提供的普通算术运算的通常抽象。Aryan’s answer中提到的converter是探索其工作原理的一个很好的方法。
不幸的是,这段代码不是符合标准的C++(或者,事实上,C),这要归功于一个叫做strict aliasing的小东西。如果一个变量被声明为整数类型,那么它只能通过指向相同整数类型的指针来访问。2不允许通过指向不同类型的指针来访问它。
一个或多或少官方认可的版本是:

inline static float float_from_bits(std::uint32_t x) {
    float result;
    static_assert(sizeof(result) == sizeof(x),
        "float must be 32 bits wide");
    std::memcpy(&result, &x, sizeof(result));
    return result;
}

或者,在C++20中,std::bit_cast<float>(x)。这仍然不能保证返回标准所期望的结果,但至少它不违反那个特定的规则。
直接的static_cast会将整数转换为表示(近似)相同数量的浮点值,这 * 不是 * 直接的位转换:执行它需要计算 sme 的适当值,并根据数字格式将它们放在适当的位置。

相关问题