将浮点值从big endian转换为little endian

Bla*_*de3 17 c++ endianness

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

我究竟做错了什么?

Gre*_*ndt 31

简单地反转四个字节的工作

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;
}
Run Code Online (Sandbox Code Playgroud)

  • @Tomek:这确实_not_违反了严格的别名规则.C和C++都明确允许_any_类型的对象作为char数组访问(因此,通过`char*`).从您发布的链接中"通过联合"强制转换导致未定义的行为(从最后一个写入的联合成员读取导致未定义的行为). (18认同)
  • 我有这个代码的另一个小问题.尽管函数的名称,它根本不像ntohl()那样表现.如果结束已经是正确的,它应该什么都不做.在这里,无论如何都要交换字节. (11认同)
  • 这是完全合法的C代码,没有编译器可以破解它.我已经使用VC6,Visual Studio 2008,Visual Studio 2010和c ++ Builder 2010对其进行了测试.这些编译器都没有破坏此代码. (7认同)
  • @Tomek:对你来说这对你有害并不重要; 重要的是它的行为是否明确.通过`char*`重新解释是明确定义的(参见C++03§3.10/ 15).工会黑客不是(参见C++03§9.5/ 1).如果您熟悉该语言,那么避免未定义或实现定义的行为并不是特别困难. (5认同)
  • @Tomek:所以你更喜欢一种能够将UB调用到一个完美定义的解决方案吗?那根本没有任何意义.你说"代码是合法的,但并不意味着它有效."然后,当谈到使用工会......"(AFAIR它是可怕的UB),但似乎有用." 我不认为我听过更多不一致的论点.你怎么能说"如果你想在如此低水平的位置摆弄你,你迟早要打UB或IDB."?你在说什么?这完全是不真实的,你只需要知道你在做什么. (2认同)

Sni*_*gus 7

很久以前我发现了大致相似的东西.是好事,但是冒着自己的危险.我甚至没有编译它:

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 好吧,如果性能很重要,那么这个版本将优于执行字节改组的版本.一旦您将值读回为dword,字节改组将显示部分停顿.在这种情况下,你总是保持dword大小,它可以很好地流水线,没有档位.EA表示,我并不感到惊讶,因为游戏开发人员使用这样的功能来获取时间关键代码. (2认同)
  • `*arg = n;`? 分配给取消引用的 void 指针是否可以在不进行强制转换的情况下工作?我希望编译器会抱怨。 (2认同)

小智 5

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

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;
}
Run Code Online (Sandbox Code Playgroud)


Ant*_*gas 5

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

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;
}
Run Code Online (Sandbox Code Playgroud)

按照 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是 C++ 中未定义的行为。读取未在联合中分配的变量是无效的。它可能在大多数编译器中运行良好 - 但不看就过马路也是如此。 (3认同)