用 4 个复合字节构建 32 位浮点数
我正在尝试用 4 个复合字节构建一个 32 位浮点数。是否有比以下方法更好(或更便携)的方法来执行此操作?
#include <iostream>
typedef unsigned char uchar;
float bytesToFloat(uchar b0, uchar b1, uchar b2, uchar b3)
{
float output;
*((uchar*)(&output) + 3) = b0;
*((uchar*)(&output) + 2) = b1;
*((uchar*)(&output) + 1) = b2;
*((uchar*)(&output) + 0) = b3;
return output;
}
int main()
{
std::cout << bytesToFloat(0x3e, 0xaa, 0xaa, 0xab) << std::endl; // 1.0 / 3.0
std::cout << bytesToFloat(0x7f, 0x7f, 0xff, 0xff) << std::endl; // 3.4028234 × 10^38 (max single precision)
return 0;
}
I'm trying to build a 32-bit float out of its 4 composite bytes. Is there a better (or more portable) way to do this than with the following method?
#include <iostream>
typedef unsigned char uchar;
float bytesToFloat(uchar b0, uchar b1, uchar b2, uchar b3)
{
float output;
*((uchar*)(&output) + 3) = b0;
*((uchar*)(&output) + 2) = b1;
*((uchar*)(&output) + 1) = b2;
*((uchar*)(&output) + 0) = b3;
return output;
}
int main()
{
std::cout << bytesToFloat(0x3e, 0xaa, 0xaa, 0xab) << std::endl; // 1.0 / 3.0
std::cout << bytesToFloat(0x7f, 0x7f, 0xff, 0xff) << std::endl; // 3.4028234 × 10^38 (max single precision)
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可以使用
memcpy
(Result)或 union* (结果)
但这并不比您的代码更可移植,因为不能保证该平台是小端字节序或
float
使用 IEEE binary32 甚至sizeof(float) == 4
。(注*:如 @James,从技术上讲,标准(C++ §[class.union]/1)不允许访问联合成员
uf
。)You could use a
memcpy
(Result)or a union* (Result)
But this is no more portable than your code, since there is no guarantee that the platform is little-endian or the
float
is using IEEE binary32 or evensizeof(float) == 4
.(Note*: As explained by @James, it is technically not allowed in the standard (C++ §[class.union]/1) to access the union member
u.f
.)以下函数将表示单精度浮点值的字节按网络字节顺序打包/解包到缓冲区或从缓冲区中解包。只有 pack 方法需要考虑字节顺序,因为 unpack 方法通过将各个字节移位适当的量,然后将它们组合在一起,显式地从各个字节构造 32 位值。这些函数仅对以 32 位存储浮点数的 C/C++ 实现有效。这对于 IEEE 754-1985 浮点实现来说是正确的。
The following functions pack/unpack bytes representing a single precision floating point value to/from a buffer in network byte order. Only the pack method needs to take endianness into account since the unpack method explicitly constructs the 32-bit value from the individual bytes by bit shifting them the appropriate amount and then OR-ing them together. These functions are only valid for C/C++ implementations that store a float in 32-bits. This is true for IEEE 754-1985 floating point implementations.
您可以使用 std::copy :
这可以避免联合黑客,这在技术上是该语言不允许的。它还避免了常用的
reinterpret_cast(byte_array)
,它违反了严格的别名规则(允许将任何对象重新解释为char
数组,因此此解决方案中的reinterpret_cast
不会违反严格的别名规则)。它仍然依赖于
float
宽度为四个字节,并依赖于您的四个字节是实现的浮点格式中的有效浮点数,但是您要么必须做出这些假设,要么必须编写特殊的处理代码来进行转换。You can use
std::copy
:This avoids the union hack, which isn't technically allowed by the language. It also avoids the commonly used
reinterpret_cast<float*>(byte_array)
, which violates the strict aliasing rules (it is permitted to reinterpret any object as an array ofchar
, so thereinterpret_cast
s in this solution do not violate the strict aliasing rules).It still relies on
float
being four bytes in width and relies on your four bytes being a valid floating point number in your implementation's floating point format, but you either have to make those assumptions or you have to write special handling code to do the conversion.没有办法做到这一点可移植,因为不同的平台可以使用:
我也想知道你从哪里得到这 4 个字节?
如果我假设您从另一个系统获取它们,并且可以保证两个系统使用完全相同的方法在内存中存储浮点值,则可以使用联合技巧。否则,你的代码几乎肯定是不可移植的。
There's no way to do this portable, since different platforms can use:
I also wonder where you get these 4 bytes from?
If I assume that you get them from another system, and you can guarantee that both systems use exactly the same method to store floating-point values in memory, you can use the union trick. Otherwise, your code is almost guaranteed to be non-portable.
如果您想要一种可移植的方式来执行此操作,则必须编写一些代码来检测系统的字节顺序。
If you want a portable way to do this, you'll have to write a bit of code to detect the endianess of the system.
我通常在 C 中使用它——不需要
memcpy
或union
。我不知道它可能会违反 C++ 中的别名规则。如果您有一个完整的字节数组需要重新解释为浮点数,则如有必要,您可以对数组中每个连续的 4 个字节序列调用以下过程,以切换字节顺序(例如,如果您运行在小端机器,但字节按大端顺序)。然后,您可以简单地将
uint8_t *
数组指针转换为float *
,并以浮点数数组的形式访问内存。I typically use this in C -- no
memcpy
orunion
required. It may break aliasing rules in C++, I don't know.If you have a whole array of bytes that need to be re-interpreted as floats, you can call the following procedure for each consecutive sequence of 4 bytes in the array if necessary, to switch the byte order (e.g. if you are running on a little endian machine, but the bytes are in big endian order). Then you can simply cast the
uint8_t *
array pointer tofloat *
, and access the memory as an array of floats.