TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #946 5.44K
​​Оборачиваем вспять байты
#новичкам

Когда мы низкоуровнево работаем с сетью, то надо понимать, что в данных, полученных по сети, нужно реверсировать порядок байтов, чтобы правильно интерпретировать значения. Также реверсировать порядок нужно при отправке данных по сети. Это происходит из-за того, что в стеке протоколов TCP/IP принят порядок Big-endian - старший байт хранится по младшему адресу. А на большинстве хостов(десктопов и серверов) - Little-endian: младший байт хранится по младшему адресу.

Соответственно нужны функции для реверсирования байтов. Обычно для этого используют либо компиляторные интринсики:

### GCC/Clang

uint16_t swapped16 = __builtin_bswap16(value);
uint32_t swapped32 = __builtin_bswap32(value);
uint64_t swapped64 = __builtin_bswap64(value);

### MSVC:

uint16_t swapped16 = _byteswap_ushort(value);
uint32_t swapped32 = _byteswap_ulong(value);
uint64_t swapped64 = _byteswap_uint64(value);


Либо системное апи:

#include <arpa/inet.h>  // Linux/macOS
// или
#include <winsock2.h> // Windows

uint16_t network_to_host16 = ntohs(value);
uint16_t host_to_network16 = htons(value);

uint32_t network_to_host32 = ntohl(value);
uint32_t host_to_network32 = htonl(value);

uint64_t network_to_host64 = ntohll(value);
uint64_t host_to_network64 = htonll(value);


Либо какое-нибудь библиотечное решение:

#include <boost/endian/conversion.hpp>

uint32_t value = 0x12345678;
uint32_t swapped = boost::endian::endian_reverse(value);

uint32_t to_big = boost::endian::native_to_big(value);
uint32_t to_little = boost::endian::native_to_little(value);


Но в С++23 появилась стандартная функция для разворачивания порядка байтов!

template< class T >
constexpr T byteswap( T n ) noexcept;


Работает она только для интегральных типов и вот ее возможная реализация:

template<std::integral T>
constexpr T byteswap(T value) noexcept
{
static_assert(std::has_unique_object_representations_v<T>,
"T may not have padding bits");
auto value_representation = std::bit_cast<std::array<std::byte, sizeof(T)>>(value);
std::ranges::reverse(value_representation);
return std::bit_cast<T>(value_representation);
}


Результат у нее собственно ровно тот, который и ожидается:

template<std::integral T>
void dump(T v, char term = '\n')
{
std::cout << std::hex << std::uppercase << std::setfill('0')
<< std::setw(sizeof(T) * 2) << v << " : ";
for (std::size_t i{}; i != sizeof(T); ++i, v >>= 8)
std::cout << std::setw(2) << static_cast<unsigned>(T(0xFF) & v) << ' ';
std::cout << std::dec << term;
}

int main()
{
static_assert(std::byteswap('a') == 'a');

std::cout << "byteswap for U16:\n";
constexpr auto x = std::uint16_t(0xCAFE);
dump(x);
dump(std::byteswap(x));

std::cout << "\nbyteswap for U32:\n";
constexpr auto y = std::uint32_t(0xDEADBEEFu);
dump(y);
dump(std::byteswap(y));

std::cout << "\nbyteswap for U64:\n";
constexpr auto z = std::uint64_t{0x0123456789ABCDEFull};
dump(z);
dump(std::byteswap(z));
}

// OUTPUT
// byteswap for U16:
// CAFE : FE CA
// FECA : CA FE

// byteswap for U32:
// DEADBEEF : EF BE AD DE
// EFBEADDE : DE AD BE EF

// byteswap for U64:
// 0123456789ABCDEF : EF CD AB 89 67 45 23 01
// EFCDAB8967452301 : 01 23 45 67 89 AB CD EF


Как всегда стандарт запаздывает лет на 10-15-20, но хорошо, что все-таки завезли эту полезную функцию, которую можно кроссплатформенно использовать.

Use standard solutions. Stay cool.

#cpp23
  • ❤ 29
  • 👍 13
  • 😁 8
  • 🔥 5
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →