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 つの関数テンプレート、rotlrotr を説明します。

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) は、xnumeric_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::nativeendian::big と等しくなります。
  • すべてのスカラー型がリトルエンディアンの場合、endian::nativeendian::little と等しくなります。
  • それ以外の場合は、endian::nativeendian::big とも endian::little とも等しくありません。
    PDP-11のように、16ビットワードはリトルエンディアンで格納し、32ビットワードを構成する2個の16ビットワードは、ビッグエンディアンで格納するミドルエンディアンなどがこれに該当します。
以下の例は、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> ヘッダーは、ビット単位でのアクセス、操作、処理を行うための強力な機能を提供します。この章で紹介した機能を活用することで、効率的で高速なコードを書くことができます。


C++