名前空間
変種
操作

ビットフィールド

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (C++20未満)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

ビット単位の明示的なサイズを持つクラスデータメンバを宣言します。 隣接するビットフィールドメンバは同じバイトを共有するためにパックされることや複数のバイトにまたがることがあります。

ビットフィールド宣言は以下の宣言子を用いたクラスデータメンバ宣言です。

identifier(オプション) attr(オプション) : size (1)
identifier(オプション) attr(オプション) : size brace-or-equal-initializer (2) (C++20以上)

ビットフィールドの宣言の構文decl-specifier-seq によって導入されます。

attr(C++11) - オプショナルな任意個の属性の並び。
identifier - 宣言されているビットフィールドの名前。 名前はオプショナルです。 名前のないビットフィールドは指定されたビット数のパディングを導入します。
size - ゼロ以上の値を持つ整数定数式。 ゼロより大きいとき、これはそのビットフィールドが占めるビット数です。 値ゼロは名前のないビットフィールドに対してのみ使用でき、クラス定義内の次のビットフィールドが確保単位の境界で始まることを指定するという、特別な意味を持ちます。
brace-or-equal-initializer - このビットフィールドで使用されるデフォルトメンバ初期化子

目次

[編集] 説明

ビットフィールドのビット数は、保持できる値の範囲の制限を設定します。

#include <iostream>
struct S {
 // 3ビットの符号なしフィールド。
 // 格納できる値は 0~7 です。
 unsigned int b : 3;
};
int main()
{
    S s = {6};
    ++s.b; // 値 7 をビットフィールドに格納します。
    std::cout << s.b << '\n';
    ++s.b; // 値 8 はこのビットフィールドには治りません。
    std::cout << s.b << '\n'; // 形式的には処理系定義、一般的には 0 です。
}

出力例:

7
0

複数の隣接するビットフィールドは、通常、一緒にパックされます (しかしこの動作は処理系定義です)。

#include <iostream>
struct S {
    // これは通常2バイトを占めます。
    // 3ビット: b1 の値。
    // 2ビット: 未使用。
    // 6ビット: b2 の値。
    // 2ビット: b3 の値。
    // 3ビット: 未使用。
    unsigned char b1 : 3, : 2, b2 : 6, b3 : 2;
};
int main()
{
    std::cout << sizeof(S) << '\n'; // usually prints 2
}

出力例:

2

特別なサイズゼロの無名ビットフィールドはパディングを強制的に分割させることができます。 これは次のビットフィールドが確保単位の先頭で始まることを指定します。

#include <iostream>
struct S {
    // これは通常2バイトを占めます。
    // 3ビット: b1 の値。
    // 5ビット: 未使用。
    // 6ビット: b2 の値。
    // 2ビット: b3 の値。
    unsigned char b1 : 3;
    unsigned char :0; // 新しいバイトを開始します。
    unsigned char b2 : 6;
    unsigned char b3 : 2;
};
int main()
{
    std::cout << sizeof(S) << '\n'; // 通常、 2 を表示します。
}

出力例:

2

ビットフィールドの指定されたサイズがその型のサイズより大きい場合、その値はその型によって制限されます。 std::uint8_t b : 1000; はやはり0から255までの値しか保持できません。 余分なビットは未使用のパディングになります。

ビットフィールドはバイトの先頭で開始するとは限らないため、ビットフィールドのアドレスを取ることはできません。 ビットフィールドへのポインタおよび非 const 参照はできません。 ビットフィールドから const 参照が初期化されたときは、一時オブジェクト (型はビットフィールドの型です) が作成され、そのビットフィールドの値でコピー初期化され、そしてその一時オブジェクトに参照が束縛されます。

ビットフィールドの型には整数型または列挙型のみが使用できます。

ビットフィールドは静的データメンバにできません。

ビットフィールドの prvalue はありません。 左辺値から右辺値への変換は常にそのビットフィールドのベースとなる型のオブジェクトを生成します。

ビットフィールドに対するデフォルトメンバ初期化子はありません。 int b : 1 = 0; および int b : 1 {0} は ill-formed です。 (C++20未満)

ビットフィールドのサイズとデフォルトメンバ初期化子の間で曖昧な場合は、有効なサイズを形成するトークンの最も長い並びが選択されます。

int a;
  const int b = 0;
  struct S {
    // 単純なケース。
    int x1 : 8 = 42;               // OK、「= 42」は brace-or-equal-initializer です。
    int x2 : 8 { 42 };             // OK、「{ 42 }」は brace-or-equal-initializer です。
    // 曖昧。
    int y1 : true ? 8 : a = 42;    // OK、 brace-or-equal-initializer は存在しません。
    int y2 : true ? 8 : b = 42;    // エラー、 const int へは代入できません。
    int y3 : (true ? 8 : b) = 42;  // OK、「= 42」は brace-or-equal-initializer です。
    int z : 1 || new int { 0 };    // OK、 brace-or-equal-initializer は存在しません。
  };
(C++20以上)

[編集] ノート

ビットフィールドの以下の性質は処理系定義です。

  • 符号付きビットフィールドを範囲外の値で代入または初期化した結果の値、または符号付きビットフィールドをその範囲を超えてインクリメントした結果の値。
  • クラスオブジェクト内のビットフィールドの実際の確保の詳細に関するすべて。
  • 例えば、プラットフォームによっては、ビットフィールドは複数のバイトにまたがりませんが、プラットフォームによっては、またがります。
  • また、プラットフォームによっては、ビットフィールドは左から右にパックされますが、プラットフォームによっては、右から左です。
  • signed または unsigned が明示的に指定されていない charshortintlong、 および long long のビットフィールドが符号付きか符号なしか。
  • 例えば、 int b:3; の値の範囲は、 0~7 かもしれませんし、 -4~3 かもしれません。
(C++14未満)

C プログラミング言語では、ビットフィールドの幅はベースとなる型の幅を越えることはできません。

[編集] 参考文献

  • C++11 standard (ISO/IEC 14882:2011):
  • 9.6 Bit-fields [class.bit]
  • C++98 standard (ISO/IEC 14882:1998):
  • 9.6 Bit-fields [class.bit]

[編集] 関連項目

ビットフィールドC言語リファレンス
固定長のビット配列を実装します
(クラステンプレート) [edit]