名稱空間
變體
操作

位域

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 

宣告一個具有顯式位大小的類資料成員。相鄰的位域成員可以(或不可以)被打包以共享和跨越單個位元組。

位域宣告是使用以下宣告符的類資料成員宣告

識別符號 (可選) 屬性 (可選) : 大小 (1)
識別符號 (可選) 屬性 (可選) : 大小 brace-or-equal-initializer (2) (C++20 起)

位域的型別宣告語法宣告說明符序列引入。

屬性 - (C++11 起) 任意數量的屬性序列
識別符號 - 正在宣告的位域的名稱。該名稱是可選的:無名位域引入指定數量的填充位
大小 - 一個整型常量表達式,其值大於或等於零。當大於零時,這是此位域將佔用的位數。值零僅允許用於無名位域,並具有特殊含義
brace-or-equal-initializer - 將與此位域一起使用的預設成員初始化器

目錄

[編輯] 解釋

位域的型別只能是整型(包括bool)或(可能帶有cv限定符的)列舉型別,無名位域不能用cv限定型別宣告。

位域不能是靜態資料成員

沒有位域的prvalue:左值到右值的轉換總是生成位域底層型別的物件。

位域中的位數限制了它可以持有的值的範圍

#include <iostream>
 
struct S
{
    // three-bit unsigned field, allowed values are 0...7
    unsigned int b : 3;
};
 
int main()
{
    S s = {6};
 
    ++s.b; // store the value 7 in the bit-field
    std::cout << s.b << '\n';
 
    ++s.b; // the value 8 does not fit in this bit-field
    std::cout << s.b << '\n'; // formally implementation-defined, typically 0
}

可能的輸出

7
0

多個相鄰的位域通常被打包在一起(儘管此行為是實現定義的)

#include <bit>
#include <cstdint>
#include <iostream>
 
struct S
{
    // will usually occupy 2 bytes:
    unsigned char b1 : 3; // 1st 3 bits (in 1st byte) are b1
    unsigned char    : 2; // next 2 bits (in 1st byte) are blocked out as unused
    unsigned char b2 : 6; // 6 bits for b2 - doesn't fit into the 1st byte => starts a 2nd
    unsigned char b3 : 2; // 2 bits for b3 - next (and final) bits in the 2nd byte
};
 
int main()
{
    std::cout << sizeof(S) << '\n'; // usually prints 2
 
    S s;
    // set distinguishable field values
    s.b1 = 0b111;
    s.b2 = 0b101111;
    s.b3 = 0b11;
 
    // show layout of fields in S
    auto i = std::bit_cast<std::uint16_t>(s);
    // usually prints 1110000011110111
    // breakdown is:  └┬┘├┘└┬┘└─┬──┘└┤
    //                b1 u  a   b2  b3
    // where “u” marks the unused :2 specified in the struct, and
    // “a” marks compiler-added padding to byte-align the next field.
    // Byte-alignment is happening because b2's type is declared unsigned char;
    // if b2 were declared uint16_t there would be no “a”, b2 would abut “u”.
    for (auto b = i; b; b >>= 1) // print LSB-first
        std::cout << (b & 1);
    std::cout << '\n';
}

可能的輸出

2
1110000011110111

大小為零的特殊無名位域可以強制中斷填充。它指定下一個位域從其分配單元的開頭開始

#include <iostream>
 
struct S
{
    // will usually occupy 2 bytes:
    // 3 bits: value of b1
    // 5 bits: unused
    // 2 bits: value of b2
    // 6 bits: unused
    unsigned char b1 : 3;
    unsigned char :0; // start a new byte
    unsigned char b2 : 2;
};
 
int main()
{
    std::cout << sizeof(S) << '\n'; // usually prints 2
                                    // would usually print 1 if not for
                                    // the padding break in line 11
}

可能的輸出

2

如果位域的指定大小大於其型別的大小,則值受型別限制:std::uint8_t b : 1000; 仍將保持在範圍[0255]內。額外的位是填充位

因為位域不一定從位元組的開頭開始,所以不能獲取位域的地址。不允許指向位域的指標和非const引用。當從位域初始化const引用時,會建立一個臨時物件(其型別是位域的型別),用位域的值進行復制初始化,然後引用繫結到該臨時物件。

位域沒有預設成員初始化器int b : 1 = 0;int b : 1 {0} 都是非法的。

(C++20 前)

在位域大小和預設成員初始化器之間存在歧義的情況下,選擇形成有效大小的最長詞元序列

int a;
const int b = 0;
 
struct S
{
    // simple cases
    int x1 : 8 = 42; // OK; "= 42" is brace-or-equal-initializer
    int x2 : 8 {42}; // OK; "{42}" is brace-or-equal-initializer
 
    // ambiguities
    int y1 : true ? 8 : a = 42;   // OK; brace-or-equal-initializer is absent
    int y2 : true ? 8 : b = 42;   // error: cannot assign to const int
    int y3 : (true ? 8 : b) = 42; // OK; "= 42" is brace-or-equal-initializer
    int z : 1 || new int{0};      // OK; brace-or-equal-initializer is absent
};
(C++20 起)

[編輯] 注意

位域的以下屬性是實現定義的

  • 將超出範圍的值賦給有符號位域或用其初始化,或將有符號位域遞增超出其範圍所產生的值。
  • 關於類物件中位域實際分配細節的一切。
  • 例如,在某些平臺上,位域不跨越位元組,而在其他平臺上則會。
  • 此外,在某些平臺上,位域是從左到右打包的,而在其他平臺上則是從右到左。

在C程式語言中,位域的寬度不能超過底層型別的寬度,並且未顯式宣告為signedunsignedint 位域是有符號還是無符號是實現定義的。例如,int b : 3; 在C中可能具有值範圍[07][-43],但在C++中只允許後一種選擇。

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 324 C++98 未指定賦值給位域的返回值
是否是位域
添加了位域規範
可能返回左值的運算子
CWG 739 C++98 未宣告為signedunsigned 的位域的符號
是實現定義的
與底層型別一致
CWG 2229 C++98 無名位域可以用cv限定型別宣告 已禁止
CWG 2511 C++98 位域型別中不允許使用cv限定符 位域可以有cv限定符
列舉型別

[編輯] 參考

  • C++23 標準 (ISO/IEC 14882:2024)
  • 11.4.10 位域 [class.bit]
  • C++20 標準 (ISO/IEC 14882:2020)
  • 11.4.9 位域 [class.bit]
  • C++17 標準 (ISO/IEC 14882:2017)
  • 12.2.4 位域 [class.bit]
  • C++14 標準 (ISO/IEC 14882:2014)
  • 9.6 位域 [class.bit]
  • C++11 標準 (ISO/IEC 14882:2011)
  • 9.6 位域 [class.bit]
  • C++03 標準 (ISO/IEC 14882:2003)
  • 9.6 位域 [class.bit]
  • C++98 標準 (ISO/IEC 14882:1998)
  • 9.6 位域 [class.bit]

[編輯] 另請參閱

實現固定長度位陣列
(類模板) [編輯]
節省空間的動態位集
(類模板特化) [編輯]
位操作 (C++20) 用於訪問、操作和處理單個位和位序列的實用工具
C文件 關於 位域