我正在尝试用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;
}
答案 0 :(得分:27)
您可以使用memcpy
(Result)
float f;
uchar b[] = {b3, b2, b1, b0};
memcpy(&f, &b, sizeof(f));
return f;
或工会*(Result)
union {
float f;
uchar b[4];
} u;
u.b[3] = b0;
u.b[2] = b1;
u.b[1] = b2;
u.b[0] = b3;
return u.f;
但这不比你的代码更便携,因为无法保证平台是little-endian或float
使用IEEE binary32甚至是sizeof(float) == 4
。
(注意*:正如@James所解释的那样,技术上不允许在标准(C ++§[class.union] / 1)中访问联合成员u.f
。)
答案 1 :(得分:15)
以下函数以网络字节顺序打包/解压缩表示缓冲区中单个精度浮点值的字节。只有pack方法需要考虑字节序,因为unpack方法显式地构造了来自各个字节的32位值,通过将它们移位适当的量然后将它们进行OR运算。这些函数仅对以32位存储浮点数的C / C ++实现有效。这适用于IEEE 754-1985浮点实现。
// unpack method for retrieving data in network byte,
// big endian, order (MSB first)
// increments index i by the number of bytes unpacked
// usage:
// int i = 0;
// float x = unpackFloat(&buffer[i], &i);
// float y = unpackFloat(&buffer[i], &i);
// float z = unpackFloat(&buffer[i], &i);
float unpackFloat(const void *buf, int *i) {
const unsigned char *b = (const unsigned char *)buf;
uint32_t temp = 0;
*i += 4;
temp = ((b[0] << 24) |
(b[1] << 16) |
(b[2] << 8) |
b[3]);
return *((float *) &temp);
}
// pack method for storing data in network,
// big endian, byte order (MSB first)
// returns number of bytes packed
// usage:
// float x, y, z;
// int i = 0;
// i += packFloat(&buffer[i], x);
// i += packFloat(&buffer[i], y);
// i += packFloat(&buffer[i], z);
int packFloat(void *buf, float x) {
unsigned char *b = (unsigned char *)buf;
unsigned char *p = (unsigned char *) &x;
#if defined (_M_IX86) || (defined (CPU_FAMILY) && (CPU_FAMILY == I80X86))
b[0] = p[3];
b[1] = p[2];
b[2] = p[1];
b[3] = p[0];
#else
b[0] = p[0];
b[1] = p[1];
b[2] = p[2];
b[3] = p[3];
#endif
return 4;
}
答案 2 :(得分:14)
您可以使用std::copy
:
float bytesToFloat(uchar b0, uchar b1, uchar b2, uchar b3)
{
uchar byte_array[] = { b3, b2, b1, b0 };
float result;
std::copy(reinterpret_cast<const char*>(&byte_array[0]),
reinterpret_cast<const char*>(&byte_array[4]),
reinterpret_cast<char*>(&result));
return result;
}
这可以避免联合黑客攻击,这在技术上是不允许的。它还避免了常用的reinterpret_cast<float*>(byte_array)
,它违反了严格的别名规则(允许将任何对象重新解释为char
数组,因此此解决方案中的reinterpret_cast
不会违反严格的别名规则)。
它仍然依赖于float
宽度为四个字节,并且依赖于您的四个字节是实现的浮点格式中的有效浮点数,但您要么必须做出这些假设,要么必须编写特殊的处理代码进行转换。
答案 3 :(得分:4)
由于不同的平台可以使用,因此无法使用便携式设备:
我也想知道你从哪里得到这4个字节?
如果我假设你从另一个系统获得它们,并且你可以保证两个系统使用完全相同的方法在内存中存储浮点值,你可以使用联合技巧。否则,您的代码几乎可以保证不可移植。
答案 4 :(得分:3)
如果您想以便携方式执行此操作,则必须编写一些代码来检测系统的字节顺序。
float bytesToFloatA(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;
}
float bytesToFloatB(uchar b0, uchar b1, uchar b2, uchar b3)
{
float output;
*((uchar*)(&output) + 3) = b3;
*((uchar*)(&output) + 2) = b2;
*((uchar*)(&output) + 1) = b1;
*((uchar*)(&output) + 0) = b0;
return output;
}
float (*correctFunction)(uchar b0, uchar b1, uchar b2, uchar b3) = bytesToFloatA;
if ((*correctFunction)(0x3e, 0xaa, 0xaa, 0xab) != 1.f/3.f) // horrifying, I know
{
correctFunction = bytesToFloatB;
}
答案 5 :(得分:0)
我通常在C语言中使用它-不需要2020-07-04 02:35:00.970071+0100 AppName [27829:919355] This is value1
2020-07-04 02:35:00.970390+0100 AppName [27829:919355] This is value2
2020-07-04 02:35:00.970557+0100 AppName[27829:919355] This is value2
或memcpy
。我不知道,它可能会破坏C ++中的别名规则。
union
如果有一个完整的字节数组需要重新解释为浮点数,则可以在必要时对数组中每个连续的4个字节序列调用以下过程,以切换字节顺序(例如,如果在小型Endian机器上运行,但字节按Big Endian顺序排列)。然后,您可以简单地将float bytesToFloat(uint8_t *bytes, bool big_endian) {
float f;
uint8_t *f_ptr = (uint8_t *) &f;
if (big_endian) {
f_ptr[3] = bytes[0];
f_ptr[2] = bytes[1];
f_ptr[1] = bytes[2];
f_ptr[0] = bytes[3];
} else {
f_ptr[3] = bytes[3];
f_ptr[2] = bytes[2];
f_ptr[1] = bytes[1];
f_ptr[0] = bytes[0];
}
return f;
}
数组指针转换为uint8_t *
,并以浮点数组的形式访问内存。
float *