将浮点值从大端转换为小端

问题描述 投票:0回答:11

是否可以将

float
从大端转换为小端?我有来自 PowerPC 平台的大端值,我通过 TCP 将其发送到 Windows 进程(小端值)。这个值是一个
float
,但是当我
memcpy
将该值转换为 Win32 float 类型,然后对该值调用
_byteswap_ulong
时,我总是得到 0.0000?

我做错了什么?

c++ endianness
11个回答
41
投票

简单地反转四个字节就可以了

float ReverseFloat( const float inFloat )
{
   float retVal;
   char *floatToConvert = ( char* ) & inFloat;
   char *returnFloat = ( char* ) & retVal;

   // swap the bytes into a temporary buffer
   returnFloat[0] = floatToConvert[3];
   returnFloat[1] = floatToConvert[2];
   returnFloat[2] = floatToConvert[1];
   returnFloat[3] = floatToConvert[0];

   return retVal;
}

12
投票

这是一个可以反转任何类型的字节顺序的函数。

template <typename T>
T bswap(T val) {
    T retVal;
    char *pVal = (char*) &val;
    char *pRetVal = (char*)&retVal;
    int size = sizeof(T);
    for(int i=0; i<size; i++) {
        pRetVal[size-1-i] = pVal[i];
    }

    return retVal;
}

9
投票

我很久以前就发现了大致类似的东西。这对于很有好处,但摄入后果自负。我什至还没有编译它:

void * endian_swap(void * arg)
{
    unsigned int n = *((int*)arg);
    n = ((n >>  8) & 0x00ff00ff) | ((n <<  8) & 0xff00ff00);
    n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
    *arg = n;   

    return arg;
}

7
投票

进行字节交换的一种优雅方法是使用联合:

float big2little (float f)
{
    union
    {
        float f;
        char b[4];
    } src, dst;

    src.f = f;
    dst.b[3] = src.b[0];
    dst.b[2] = src.b[1];
    dst.b[1] = src.b[2];
    dst.b[0] = src.b[3];
    return dst.f;
}

按照 jjmerelo 建议编写一个循环,更通用的解决方案可能是:

typedef float number_t;
#define NUMBER_SIZE sizeof(number_t)

number_t big2little (number_t n)
{
    union
    {
        number_t n;
        char b[NUMBER_SIZE];
    } src, dst;

    src.n = n;
    for (size_t i=0; i<NUMBER_SIZE; i++)
        dst.b[i] = src.b[NUMBER_SIZE-1 - i];

    return dst.n;
}

3
投票

不要将数据直接memcpy到float类型中。将其保留为 char 数据,交换字节,然后然后 将其视为浮点数。


2
投票

来自 SDL_endian.h,略有改动:

std::uint32_t Swap32(std::uint32_t x)
{
    return static_cast<std::uint32_t>((x << 24) | ((x << 8) & 0x00FF0000) |
                                      ((x >> 8) & 0x0000FF00) | (x >> 24));
}

float SwapFloat(float x)
{
    union
    {
        float f;
        std::uint32_t ui32;
    } swapper;
    swapper.f = x;
    swapper.ui32 = Swap32(swapper.ui32);
    return swapper.f;
}

1
投票

使用ntoa和相关函数从网络到主机以及从主机到网络的转换可能会更容易......它的优点是可移植的。 这里是一篇文章的链接,解释了如何执行此操作。


0
投票

这个值是一个浮点数,但是当我将值“memcpy”到win32浮点类型中,然后对该值调用

_byteswap_ulong
时,我总是得到0.0000?

这应该有效。你能发布你的代码吗?

但是,如果您关心性能(也许您不关心,在这种情况下您可以忽略其余部分),应该可以避免 memcpy,方法是直接将其加载到目标位置并交换那里的字节,或者使用swap 在复制时进行交换。


0
投票

在某些情况下,尤其是在 modbus 上:浮点数的网络字节顺序是:

nfloat[0] = float[1]
nfloat[1] = float[0]
nfloat[2] = float[3]
nfloat[3] = float[2]

0
投票

@morteza@AnotherParker 已经提到了 Boost 库,指出对

float
的支持已被删除。然而,自从他们写下评论后,它就被添加回库的一个子集中。

使用 Boost.Endian 转换函数,版本 1.77.0 当我写这个答案时,你可以执行以下操作:

float input = /* some value */;
float reversed = input;
boost::endian::endian_reverse_inplace(reversed);

查看常见问题解答以了解为什么支持被删除然后部分添加回来(主要是因为反转的

float
可能不再有效)并此处了解支持历史记录。


0
投票

快速破解:

#define FBIT32_REVERSE(val) htonl(*(long*) &val)
© www.soinside.com 2019 - 2024. All rights reserved.