C++/標準ライブラリ/bit
C++教科書/標準ライブラリ編/<bit>の章
[編集]はじめに
[編集]<bit> ヘッダーは、C++20 で導入されたもので、ビット単位でのアクセス、操作、処理を行うための関数を提供します。 この章では、<bit> ヘッダーで利用できる機能について説明します。
ビット操作 (bit)
[編集]ビット操作を行うための関数は、大きく分けて以下の3つのカテゴリに分類されます。
- 一般操作 (bit.general)
- ビット列の型変換や、バイトオーダーの取得などを行います。
- ローテーション (bit.rotate)
- ビット列をビット単位で循環シフトさせます。
- カウント (bit.count)
- ビット列内にある連続した 0 や 1 の個数をカウントします。
- エンディアン (bit.endian)
- 実行環境におけるデータのバイトオーダーを確認します。
一般操作 (bit.general)
[編集]<bit> ヘッダーは、以下の機能を提供します。
- 個々のビットやビット列にアクセス、操作、処理を行うためのコンポーネント
ヘッダー概要 (bit.syn)
[編集]- C++
// all freestanding namespace std { // ... (以降の関数が続く) }
<bit> ヘッダーは、すべての関数が名前空間 std 内に宣言されています。
関数テンプレート bit_cast (bit.cast)
[編集]bit_cast 関数テンプレートは、ある型のオブジェクトを別の型のオブジェクトへとビット列のレベルで変換します。
- C++
template constexpr To bit_cast(const From& from) noexcept;
- 引数
-
From- 変換元の型のオブジェクト
To- 変換先の型のオブジェクト (型
Fromと同じサイズである必要があります)
- 戻り値
To型のオブジェクト。変換元のオブジェクトfromのビット列がそのままTo型のオブジェクトのビット列としてコピーされます。- 制約
sizeof(To)がsizeof(From)と等しいことFrom型とTo型がどちらもトリビアルにコピー可能であること
byteswap (bit.byteswap)
[編集]byteswap 関数テンプレートは、多バイト整数値のバイトオーダーを反転させます。
- C++
template constexpr T byteswap(T value) noexcept;
- 引数
-
value- バイトオーダーを変更する値
- 戻り値
valueのバイトオーダーが反転された値- 制約
valueの型は整数型であることvalueの型はパディングビットを持たないこと
2 のべき乗 (bit.pow.two)
[編集]この節では、2 のべき乗に関連する 3 つの関数テンプレートについて説明します。
- has_single_bit(x):
xが 2 のべき乗かどうかを判定します。(戻り値は真偽) - bit_ceil(x):
xよりも小さくなく、かつ 2 のべき乗である最小の値を返します。 - bit_floor(x):
xよりも大きくなく、かつ 2 のべき乗である最大の値を返します。
いずれの関数でも、引数 x は符号なし整数型である必要があります。
ローテーション (bit.rotate)
[編集]この節では、ビット列をビット単位で循環シフトさせる 2 つの関数テンプレート、rotl と rotr を説明します。
- C++
template [[nodiscard]] constexpr T rotl(T x, int s) noexcept; template [[nodiscard]] constexpr T rotr(T x, int s) noexcept;
どちらも引数として、シフトさせるビット数 s を受け取ります。s が正の場合、ビット列を左 (rotl) または右 (rotr) に s ビット分シフトさせます。s が負の場合には、符号を反転させて反対方向にシフトさせます。
カウント (bit.count)
[編集]この節では、ビット列内にある連続した 0 や 1 の個数をカウントする 4 つの関数テンプレート、countl_zero, countl_one, countr_zero, countr_one と、ビット列内の 1 の個数をカウントする関数テンプレート popcount について説明します。
- 引数
x: カウントを行うビット列- 戻り値
-
countl_zero(x)xのビット列の先頭から始まる連続した 0 の個数countl_one(x)xのビット列の先頭から始まる連続した 1 の個数countr_zero(x)xのビット列の末尾から始まる連続した 0 の個数countr_one(x)xのビット列の末尾から始まる連続した 1 の個数popcount(x)xのビット列内の 1 の個数
- 制約
xの型は符号なし整数型であること- 補足
countl_zero(x)とcountl_one(x)は、xが 0 の場合、numeric_limits::digitsを返します。countr_zero(x)とcountr_one(x)は、xが 0 の場合、numeric_limits::digitsを返します。popcount(x)は、xがnumeric_limits::max()の場合、numeric_limits::digitsを返します。
エンディアン (bit.endian)
[編集]endian 列挙型は、実行環境におけるデータのバイトオーダーを表します。
- C++
enum class endian { little = 下述, big = 下述, native = 下述 };
endian::little- ビット列の最も小さいビットが最初に配置される形式
endian::big- ビット列の最も大きいビットが最初に配置される形式
endian::native- 実行環境におけるネイティブのバイトオーダー
endian::nativeは、以下の条件によって決定されます。- すべてのスカラー型のサイズが 1 バイトの場合、
endian::little,endian::big,endian::nativeはすべて同じ値になります。 - すべてのスカラー型がビッグエンディアンの場合、
endian::nativeはendian::bigと等しくなります。 - すべてのスカラー型がリトルエンディアンの場合、
endian::nativeはendian::littleと等しくなります。 - それ以外の場合は、
endian::nativeはendian::bigともendian::littleとも等しくありません。- PDP-11のように、16ビットワードはリトルエンディアンで格納し、32ビットワードを構成する2個の16ビットワードは、ビッグエンディアンで格納するミドルエンディアンなどがこれに該当します。
- すべてのスカラー型のサイズが 1 バイトの場合、
- 例
- 以下の例は、
endian::nativeの値を確認する方法を示しています。 - C++
#include <bit> #include <iostream> auto main() -> int { switch (std::endian::native) { case std::endian::little: std::cout << "little-endian" << std::endl; break; case std::endian::big: std::cout << "big-endian" << std::endl; break; default: std::cout << "unknown endianness" << std::endl; } return 0; }
- このコードは、実行環境のバイトオーダーを出力します。
まとめ
[編集]<bit> ヘッダーは、ビット単位でのアクセス、操作、処理を行うための強力な機能を提供します。この章で紹介した機能を活用することで、効率的で高速なコードを書くことができます。