C++23標準ライブラリでは「バイト単位での順序入れ替え」を行う関数テンプレート std::byteswap
が追加されました。
C++20機能を利用したエンディアン判定(std::endian
)と組み合わせて、整数型のネットワークバイトオーダー ⇔ ホストバイトオーダー変換を汎用的に記述できます。
// <arpa/inet.h>ヘッダ
uint32_t htonl(uint32_t);
uint16_t htons(uint16_t);
uint32_t ntohl(uint32_t);
uint16_t ntohs(uint16_t);
// WindowsOSは<winsock.h>ヘッダで同等関数を宣言
#include <bit>
#include <concepts>
template <std::integral T>
constexpr inline T hton(T value) noexcept
{
if constexpr (std::endian::native == std::endian::little) {
return std::byteswap(value);
} else {
return value;
}
}
template <std::integral T>
constexpr inline T ntoh(T value) noexcept
{
if constexpr (std::endian::native == std::endian::little) {
return std::byteswap(value);
} else {
return value;
}
}
これでもう64ビット幅整数のバイトスワップ関数1を探す必要もなくなり、将来に備えて128ビット幅整数(要る?)のバイトスワップ処理だって簡単に書けちゃいます!
EXTRA STAGE
以降は onihusube🍄さん からの鋭い指摘 追加ネタご提供をもとに追記した内容です。寂しかった記事を増強させるきっかけを頂いたことに感謝。
この世の中にはリトルエンディアン/ビッグエンディアンどちらでも無い、独自の エンディアン をもつアーキテクチャが存在するそうです。例えば往年の PDP-11 とか。
C++標準ライブラリはこの点を考慮した仕様となっており、std::endian::native
はstd::endian::little
, std::endian::big
いずれでもない処理系定義の値をとる可能性があります。さすが俺たち/私たちのC++!!
#include <bit>
#include <concepts>
template <std::integral T>
constexpr inline T hton(T value) noexcept
{
if constexpr (std::endian::native == std::endian::little) {
return std::byteswap(value);
} else if constexpr (std::endian::native == std::endian::big) {
return value;
} else {
static_assert(false, "Unknown endianness");
}
}
template <std::integral T>
constexpr inline T ntoh(T value) noexcept
{
if constexpr (std::endian::native == std::endian::little) {
return std::byteswap(value);
} else if constexpr (std::endian::native == std::endian::big) {
return value;
} else {
static_assert(false, "Unknown endianness");
}
}
else節の static_assert(false, "...");
が気になったあなた。かなりC++にお詳しいですね?確かに以前のC++仕様ではこの書き方だとconstexpr if文の分岐状況によらずコンパイルエラーを引き起こしていました。2023年12年現在では プログラマの意図通りに振る舞うよう修正 されています。ちゃんとユーザフレンドリに進化してるんですね〜
関連情報
- P1272R4 Byteswapping for fun&&nuf
- P0463R1 endian, Just endian
- Stack Overflow, Integer Byte Swapping in C++
-
htonll
/ntohll
,bswap_64
,_byteswap_uint64
, etc... ↩