在c++中,什么是endian转换的最佳样式

In c++, what is the best style for endian conversion

本文关键字:转换 最佳 样式 endian c++ 什么      更新时间:2023-10-16

我正在制作一个内联函数库,用于处理测试平台端序和进行转换。。

我的第一次尝试是这样构建函数:

inline uint32_t NativeToLittle(uint32_t in)
{
    if(littleEndian())
        return in;
    else
    {
        uint32_t var = 0;
        ((uint16_t*)&var)[0] = NativeToLittle(((uint16_t*)&in)[1]);
        ((uint16_t*)&var)[1] = NativeToLittle(((uint16_t*)&in)[0]);
        return var; 
    }
}

这在一些平台上有效,但在具有激进优化选项的gcc上失败了(将uint32_t*转换为uint16_t*违反了严格的混叠规则。)

考虑到别名规则提到了并集,我重写了函数以使用并集进行转换,如下所示:

inline uint32_t swapEndian(uint32_t in)
{
    union ds
    {
        uint32_t a;
        uint16_t b[2];
    };
    ds var;
    ds out;
    var.a = in;
    out.b[0] = swapEndian(var.b[1]);
    out.b[1] = swapEndian(var.b[0]);
    return out.a;
}

这在我尝试过的所有平台上都有效,但我不清楚它是否是好的风格。我记得看到一段视频,演讲者说这种使用工会进行转换的方案是无效的,因为它只对访问工会的一名成员有效(对不起,我不记得这次演讲的网址了)。此外,Stroustrup的JSF编码标准规定"不应使用联合"。

别名规则中唯一相关的一点是,强制转换为char类型是有效的。不过,将其转换为char缓冲区并返回可能会非常难看。

所以。。构建这样既符合标准又可读的代码的最佳方式是什么?

太糟糕了。您几乎不应该检查处理器的端序。如果进行转换,则应该从外部格式的字节数组转换为内部格式,或者从内部格式转换为外部格式的字符数组。

你的职能从一开始就具有误导性。"in"参数一开始并不是真正的uint32_t。你应该写一些类似的东西

uint32_t readExternalInt (unsigned char* p) {
    return (p [aaa] << 24)  | (p [bbb] << 16) | (p [ccc] << 8) | p [ddd];
}

具有适当的aaa、bbb、ccc和ddd值。看看这短了多少?它适用于每一个处理器,无论是bigendian、littleendian、mixedian、倒置、倒立还是其他什么。

尽管我不喜欢宏,但一个合理的解决方案来自网络代码

例如,使用man-htons:

Linux Programmer's Manual 
NAME
   htonl,  htons,  ntohl,  ntohs - convert values between host and network
   byte order
SYNOPSIS
   #include <arpa/inet.h>
   uint32_t htonl(uint32_t hostlong);
   uint16_t htons(uint16_t hostshort);
   uint32_t ntohl(uint32_t netlong);
   uint16_t ntohs(uint16_t netshort);
DESCRIPTION
   The htonl() function converts the unsigned integer hostlong  from  host
   byte order to network byte order.
....
inline uint32_t swapEndian(uint32_t in)
{
    return (in >> 24) &  0xFF         |   //move byte 3 to byte 0
           (in >> 8)  & (0xFF << 8)   |   //move byte 2 to byte 1
           (in << 8)  & (0xFF << 16)  |   //move byte 1 to byte 2
           (in << 24) & (0xFF << 24); |   //move byte 0 to byte 1
}