做 reinterpret_cast 时字节顺序对网络字节顺序的影响

Effect of endianness on network byte order when doing reinterpret_cast

我正在尝试将 IP 地址的字符串表示形式与其字节表示形式相互转换。为简单起见,我们只讨论 IPv4 地址,因为字节顺序会以相同的方式影响这两种 IP 地址。

给定一个 "168.212.226.204" 形式的字符串,我创建一个长度为 4 的数组,存储 IP 地址的每个字节。

代码如下:

std::array<uint8_t, 4> IpAddress;
const char* addr_str = "168.212.226.204";
struct in_addr in_addr = {};
if (inet_pton(AF_INET, addr_str , &in_addr) == 1) // successful conversion
{
    uint8_t* addr = reinterpret_cast<uint8_t*>(&(in_addr.s_addr));
    for (size_t i = 0; i < 4; i++)
    {
        IpAddress[i] = addr[i];
    }
  }

inet_pton 函数 returns 其结果采用网络字节顺序(大端),并且因为我将结果重新解释为字节数组,所以我确信 ipAdress[0] 将始终包含 IP 地址的 MSB。所以在这方面,字节顺序应该完全不是问题。

对于从字节数组到字符串的转换,我执行以下操作:

char ip_str[INET_ADDRSTRLEN];
struct in_addr ip_addr = {};
ip_addr.s_addr = *(reinterpret_cast<uint32_t*>(IpAddress.data()));

if (inet_ntop(AF_INET, &ip_addr, ip_str, INET_ADDRSTRLEN) != NULL)
{
  return std::string(ip_str);
}

现在,根据机器的字节顺序,重新解释转换 IpAddress 的数据将导致不同的 uint32_t,但由于我将值分配给 in_addr,只是为了调用 inet_ntop,我仍然希望这段代码可以在任何平台上运行,即使 inet_ntop 需要网络字节顺序。我的代码正确吗?

编辑: 我有一台小端机器,它工作正常。最后,返回的字符串等于我开始的字符串 ("168.212.226.204").

Is my code correct?

不是,但问题不在于字节顺序。

首先,关于字节顺序,您通过强制转换指针加载的 32 位值将按网络字节顺序排列。由于您不对其进行解释或转换,而只是将其存储到另一个位置,因此该存储值仍将采用适合 inet_ntop 的网络字节顺序。在任何平台上都是如此。请注意,您使用无符号整数来传输值的事实在这里是必不可少的,因为允许带符号整数具有陷阱表示,并且在这种情况下从内存中加载任意值可能会导致未定义的行为。

问题是取消引用强制转换的指针需要适当对齐内存,而您的代码不能保证这一点。您需要将 IpAddress 强制对齐到 4 个字节(例如使用 alignas)或使用不同的方法来传输不需要对齐的值,例如 memcpy。后者更可取,因为它更清楚地表达了你的意图。

std::memcpy(&ip_addr.s_addr, IpAddress.data(), IpAddress.size());