Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从4个复合字节中构建32位浮点_C++_Floating Point_Endianness_Portability_Single Precision - Fatal编程技术网

C++ 从4个复合字节中构建32位浮点

C++ 从4个复合字节中构建32位浮点,c++,floating-point,endianness,portability,single-precision,C++,Floating Point,Endianness,Portability,Single Precision,我试图用它的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)

我试图用它的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;
}
#包括
typedef无符号字符;
通过测试浮点数(uchar b0、uchar b1、uchar b2、uchar b3)
{
浮动输出;
*((uchar*)(&output)+3)=b0;
*((uchar*)(&output)+2)=b1;
*((uchar*)(&output)+1)=b2;
*((uchar*)(&output)+0)=b3;
返回输出;
}
int main()
{

std::cout您可以使用
memcpy
()

或工会*()

但这并不比您的代码更具可移植性,因为无法保证平台是little endian或
float
使用IEEE binary32,甚至
sizeof(float)==4


(注*:如所述,标准(C++§[class.union]/1)技术上不允许访问工会成员
u.f

您可以使用
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;
} 
float bytesToFloat(uchar b0、uchar b1、uchar b2、uchar b3)
{ 
uchar字节_数组[]={b3,b2,b1,b0};
浮动结果;
std::copy(重新解释转换(&字节数组[0]),
重新解释字节转换(&字节数组[4]),
重新解释铸造(结果));
返回结果;
} 
这避免了该语言在技术上不允许的联合攻击。它还避免了常用的
重新解释转换(字节数组)
,这违反了严格的别名规则(允许将任何对象重新解释为
char
数组,因此此解决方案中的
reinterpret\u cast
s不会违反严格的别名规则)


它仍然依赖于
float
是四个字节的宽度,并且依赖于您的四个字节是实现的浮点格式中的有效浮点数,但是您必须做出这些假设,或者您必须编写特殊的处理代码来进行转换。

如果您想要一种可移植的方式来实现这一点,您必须编写一段代码来检测系统的持久性

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;
}

由于不同的平台可以使用:

  • 不同的字节顺序(大端与小端)
  • 浮点值的不同表示形式(请参见示例)
  • 浮点值的不同大小
我还想知道这4个字节是从哪里来的


如果我假设您从另一个系统获取它们,并且您可以保证两个系统使用完全相同的方法在内存中存储浮点值,那么您可以使用union技巧。否则,您的代码几乎可以保证是不可移植的。

以下函数打包/解包表示单精度浮点点的字节以网络字节顺序向缓冲区发送/从缓冲区发送的t值。只有pack方法需要考虑endianness,因为unpack方法通过将单个字节位移位适当的量,然后将它们合并在一起,从而显式地从单个字节构造32位值。这些函数仅对存储浮点值的C/C++实现有效32位。这对于浮点实现是正确的

// 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;
}
//用于检索网络字节中数据的解包方法,
//大端号,顺序(MSB优先)
//按未打包的字节数递增索引i
//用法:
//int i=0;
//float x=解包float(&buffer[i],&i);
//浮动y=浮动(&缓冲区[i],&i);
//float z=解包float(&buffer[i],&i);
浮点数解压浮点数(常数void*buf,int*i){
常量无符号字符*b=(常量无符号字符*)buf;
uint32温度=0;
*i+=4;

(b(0)我通常在C中使用这一点——没有<代码> MeMCPY 或 CUng/<代码>。它可能会破坏C++中的混叠规则,我不知道。
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;
}
如果需要将整个字节数组重新解释为浮点数,则可以在必要时对数组中每个连续的4字节序列调用以下过程,以切换字节顺序(例如,如果在小端计算机上运行,但字节顺序为大端)。然后,您可以简单地将
uint8\u t*
数组指针强制转换为
float*
,并以float数组的形式访问内存

void switchEndianness(uint8_t *bytes) {
    uint8_t b0 = bytes[0];
    uint8_t b1 = bytes[1];
    uint8_t b2 = bytes[2];
    uint8_t b3 = bytes[3];
    bytes[0] = b3;
    bytes[1] = b2;
    bytes[2] = b1;
    bytes[3] = b0;
}

@JoshD:没有;它仍然依赖于
sizeof(float)==4
,并且没有考虑端点。它只是避免了
reinterpret\u cast(一些数组)
和union hack。我相当肯定,如果字节数组(1)正确对齐,那么必须允许
reinterpret\u cast(字节数组)
实际上包含一个浮点数。我这样认为是因为,否则就不可能将
memcpy
a
float
写入另一个
float
(因为
memcpy
写入字节数组),而
float
是典型的POD类型。@MSalters:但是
memcpy
不会将字节数组重新解释为float;它会将float重新解释为字节数组。它确实不是
memcpy
本身;它显然只在字节数组上起作用。这保证了您可以将输出字节数组用作float。要解决
sizeof(float)
问题您可以将
b
成员声明为
uchar b[sizeof(float)]
@Matteo:是的,但是输入也需要修改。这在任何尾数中都是不相等的,因为
1./3。
双精度
,而不是
浮点数
。你应该使用类似
1.0f/3
。考虑到这是我关于堆栈溢出的第一个问题,我对各种回答感到兴奋。谢谢你对于输入,我认为代码行中有一个错误:返回*((浮点*)临时参数);它应该是:返回*((浮点*)和临时参数);我很确定,这是由于严格的混叠规则在C++中的未定义行为。
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;
}
void switchEndianness(uint8_t *bytes) {
    uint8_t b0 = bytes[0];
    uint8_t b1 = bytes[1];
    uint8_t b2 = bytes[2];
    uint8_t b3 = bytes[3];
    bytes[0] = b3;
    bytes[1] = b2;
    bytes[2] = b1;
    bytes[3] = b0;
}