Я играю с прямым и прямым порядком преобразования и нашел кое-что, что немного сбивает с толку, но также и интересно.
В первом примере нет проблем с использованием битового сдвига для преобразования порядка байтов для типа 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
ниже, компилятор выдает предупреждение о том, что 'ширина [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);
}
Меня немного смущают Example #1
и Example #2
, насколько я понимаю, оба s[i]
имеют uint8_t
размер, но каким-то образом, если он сдвигает только 32 бита или меньше, проблем нет вообще, но есть проблема при сдвиге, как 56 бит. Я запускаю эту программу в Ubuntu с G CC 8.3.0.
В этом случае компилятор неявно преобразует s[i]
в 32-разрядные числа? sizeof(s[0])
равно 1, когда я добавил к этому отладочные сообщения.