我看过这个演员阵容:
const std::uint32_t tmp = (some number); float ToFloat = *(float*)(&tmp);
但是在强制转换的时候,错误的数字进入了浮点数。而且,如果我使用静态强制转换,那么它是正确的。1.为什么会这样呢?
*(float*)(&Tmp)
&tmp
cczfrluj1#
为什么会这样呢?程序有未定义的行为,因为你通过float的眼睛从int读取。这在C++中是不允许的。static_cast究竟是如何工作的?在本例中,它执行与float ToFloat = Tmp;相同的转换,即,将int转换为float并将其赋值给ToFloat。*(float*)(&Tmp)意味着我们试图解引用指向浮点数的指针,该指针位于地址& Tmp处,对吗?在&Tmp处没有float,只有int。然而,您告诉编译器指针指向float并解引用该指针。int s和float s的位模式非常不同,因此不仅它具有未定义的行为,而且您将很难得到正确的结果。
float
int
float ToFloat = Tmp;
ToFloat
&Tmp
bjp0bcyl2#
整数以二进制(基数为2)表示形式存储。int32_t占用32位。
int32_t
在大多数的C++编译器中,使用一个叫做IEEE754的标准来存储浮点数和双精度数,这与整数的存储方式有很大的不同。您可以使用某种IEEE-754 Floating Point Converter检查数字是如何存储的。
让我们考虑数字5的一个简单例子。
const uint Tmp = 5;
Tmp将作为0x00000005存储在存储器中,因此&Tmp将指向相同的值。
Tmp
0x00000005
float ToFloat = *(float*)(&Tmp);
将其转换为浮点指针会将0x00000005视为IEEE 754格式,其值为7.00649232162e-45。
7.00649232162e-45
静态强制转换使用安全隐式转换在兼容类型之间执行转换。请注意,您的问题是将int*转换为float*,这不是一个安全的转换。您可以安全地将int转换为float。
int*
float*
const uint32_t Tmp = 5; float ToFloat = (float)Tmp; // 5
更多关于static_cast conversion的信息。
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会将整数转换为表示(近似)相同数量的浮点值,这 * 不是 * 直接的位转换:执行它需要计算 s、m 和 e 的适当值,并根据数字格式将它们放在适当的位置。
std::bit_cast<float>(x)
static_cast
3条答案
按热度按时间cczfrluj1#
为什么会这样呢?
程序有未定义的行为,因为你通过
float
的眼睛从int
读取。这在C++中是不允许的。static_cast究竟是如何工作的?
在本例中,它执行与
float ToFloat = Tmp;
相同的转换,即,将int
转换为float
并将其赋值给ToFloat
。*(float*)(&Tmp)
意味着我们试图解引用指向浮点数的指针,该指针位于地址& Tmp处,对吗?在
&Tmp
处没有float
,只有int
。然而,您告诉编译器指针指向float
并解引用该指针。int
s和float
s的位模式非常不同,因此不仅它具有未定义的行为,而且您将很难得到正确的结果。bjp0bcyl2#
存储整数
整数以二进制(基数为2)表示形式存储。
int32_t
占用32位。储存彩车
在大多数的C++编译器中,使用一个叫做IEEE754的标准来存储浮点数和双精度数,这与整数的存储方式有很大的不同。
您可以使用某种IEEE-754 Floating Point Converter检查数字是如何存储的。
示例
让我们考虑数字5的一个简单例子。
Tmp
将作为0x00000005
存储在存储器中,因此&Tmp
将指向相同的值。将其转换为浮点指针会将
0x00000005
视为IEEE 754格式,其值为7.00649232162e-45
。静态转换
静态强制转换使用安全隐式转换在兼容类型之间执行转换。
请注意,您的问题是将
int*
转换为float*
,这不是一个安全的转换。您可以安全地将int
转换为float
。更多关于static_cast conversion的信息。
kx7yvsdv3#
这段代码尝试将浮点数的32位表示形式转换为实际的浮点值。(大多数情况下)形式的数的表示(−1)s × m × 2e。对于给定的浮点格式,机器字中的一定数量的位被分配给每个 s(符号位),m(尾数或有效位)和 e 可在位表示内直接操纵那些位以便构造任何可能的浮点值,从而绕过由语言提供的普通算术运算的通常抽象。Aryan’s answer中提到的converter是探索其工作原理的一个很好的方法。
不幸的是,这段代码不是符合标准的C++(或者,事实上,C),这要归功于一个叫做strict aliasing的小东西。如果一个变量被声明为整数类型,那么它只能通过指向相同整数类型的指针来访问。2不允许通过指向不同类型的指针来访问它。
一个或多或少官方认可的版本是:
或者,在C++20中,
std::bit_cast<float>(x)
。这仍然不能保证返回标准所期望的结果,但至少它不违反那个特定的规则。直接的
static_cast
会将整数转换为表示(近似)相同数量的浮点值,这 * 不是 * 直接的位转换:执行它需要计算 s、m 和 e 的适当值,并根据数字格式将它们放在适当的位置。