在c / c ++中优化和便携地转换endian

给定一个需要解析的32位小尾数字段的二进制文件,我想编写解析代码,这些代码正确编译,而不依赖于执行该代码的机器的字节顺序。 目前我使用

uint32_t fromLittleEndian(const char* data){
  return uint32_t(data[3]) << (CHAR_BIT*3) |
         uint32_t(data[2]) << (CHAR_BIT*2) |
         uint32_t(data[1]) << CHAR_BIT |
         data[0]; 
}

但是,这会产生不理想的组装。 在我的机器上g++ -O3 -S产生:

_Z16fromLittleEndianPKc:
.LFB4:
    .cfi_startproc
    movsbl  3(%rdi), %eax
    sall    $24, %eax
    movl    %eax, %edx
    movsbl  2(%rdi), %eax
    sall    $16, %eax
    orl %edx, %eax
    movsbl  (%rdi), %edx
    orl %edx, %eax
    movsbl  1(%rdi), %edx
    sall    $8, %edx
    orl %edx, %eax
    ret
    .cfi_endproc

为什么发生这种情况? 我如何说服它在小端机器上编译时产生最优代码:

_Z17fromLittleEndian2PKc:
.LFB5:
    .cfi_startproc
    movl    (%rdi), %eax
    ret
    .cfi_endproc

我通过编译得到:

uint32_t fromLittleEndian2(const char* data){
    return *reinterpret_cast<const uint32_t*>(data);
}

因为我知道我的机器是小端的,所以我知道上面的程序集是最优的,但是如果在big-endian机器上编译,它会失败。 它也违反了严格的别名规则,所以如果内联它可能会在小端机器上产生UB。 如果可能 ,是否有一个有效的代码将被编译为最优组装?

由于我期望我的函数内联很多,所以任何类型的运行时endian检测都是不可能的。 编写最佳C / C ++代码的唯一选择是使用编译时endian检测,如果目标endian不是little-endian,则使用template s或#define s回退到低效代码。 然而,这似乎是相当难以轻松完成的。


我知道的各种平台库都是通过#根据#define BIG_ENDIAN的值定义端到端交换例程的宏来完成的。 在源字节顺序与目标字节顺序匹配的情况下,您可以:

#ifdef LITTLE_ENDIAN
    #define fromLittleEndian(x) (x)
#else
    #define fromLittleEndian(x) _actuallySwapLittle((x))
#endif

例如:

http://man7.org/linux/man-pages/man3/endian.3.html

http://fxr.watson.org/fxr/source/sys/endian.h


简短的答案 - 使用htonl - 它将会在wazzoo中得到优化

链接地址: http://www.djcxy.com/p/33525.html

上一篇: Optimal and portable conversion of endian in c/c++

下一篇: How to fix the Disappearing/Invisible/Empty UITableViewCells issue in Swift?