【发布时间】:2020-02-28 18:17:40
【问题描述】:
我正在玩 little endian/big endian 转换,发现 a 有点令人困惑但也很有趣。
在第一个示例中,使用位移来转换uint32_t 类型的字节顺序没有问题。它基本上将uint32_t 整数转换为uint8_t 数组并尝试访问每个字节和位移位。
示例 #1:
uint32_t htonl(uint32_t x)
{
uint8_t *s = (uint8_t*)&x;
return (uint32_t)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]);
}
但是,如果我尝试在下面的 uint64_t 上做类似的事情,编译器会抛出关于“s[0] 宽度小于 56 位”的警告,如下面的示例 #2 所示。
示例 #2:
uint64_t htonl(uint64_t x)
{
uint8_t *s = (uint8_t*)&x;
return (uint64_t)(s[0] << 56 ......);
}
为了使其工作,我必须将每个字节提取到 uint64_t 中,这样我就可以进行位移而不会出现任何错误,如下面的示例 #3 所示。
示例 #3:
uint64_t htonll2(uint64_t x)
{
uint64_t byte1 = x & 0xff00000000000000;
uint64_t byte2 = x & 0x00ff000000000000;
uint64_t byte3 = x & 0x0000ff0000000000;
uint64_t byte4 = x & 0x000000ff00000000;
uint64_t byte5 = x & 0x00000000ff000000;
uint64_t byte6 = x & 0x0000000000ff0000;
uint64_t byte7 = x & 0x000000000000ff00;
uint64_t byte8 = x & 0x00000000000000ff;
return (uint64_t)(byte1 >> 56 | byte2 >> 40 | byte3 >> 24 | byte4 >> 8 |
byte5 << 8 | byte6 << 24 | byte7 << 40 | byte8 << 56);
}
我对@987654329@ 和Example #2 有点困惑,据我了解,s[i] 的大小均为uint8_t,但不知何故,如果它只移动 32 位或更少,则在全部,但是在像 56 位一样移动时会出现问题。我在带有 GCC 8.3.0 的 Ubuntu 上运行这个程序。
在这种情况下,编译器是否会将s[i] 隐式转换为 32 位数字?当我向其中添加调试消息时,sizeof(s[0]) 为 1。
【问题讨论】: