Spec-Zone.ru › C++

Поле битовой маски

Объявляет член данных класса со явным размером в битах. Смежные члены битовой маски могут (или не могут) быть упакованы для совместного использования и перекрытия отдельных байтов.

Объявление битовой маски — это объявление члена данных класса, которое использует следующий декларатор:

идентификатор (необязательно) атрибут (необязательно) : размер (1)
идентификатор (необязательно) атрибут (необязательно) : размер инициализатор_скобки_или_равно (2) (с C++20)

Тип битовой маски вводится последовательностью_спецификаторов_типа синтаксиса объявления.

атрибут - (с C++11) последовательность любого количества атрибутов
идентификатор - имя битовой маски, которая объявляется. Имя необязательно: безымянные битовые маски вводят указанное количество битов_заполнения.
размер - целочисленное константное выражение со значением больше или равно нулю. При значении больше нуля это количество битов, которое будет занимать эта битовая маска. Значение ноль разрешено только для безымянных битовых масок и имеет специальное значение.
инициализатор_скобки_или_равно - инициализатор_члена_по_умолчанию, который будет использоваться с этой битовой маской

Объяснение

Тип битовой маски может быть только целочисленным или (возможно, с квалификаторами cv) типом перечисления, безымянную битовую маску нельзя объявить с типом, имеющим квалификаторы cv.

Битовая маска не может быть статическим членом данных.

Для битовых масок нет временных значений: преобразование lvalue в rvalue всегда создаёт объект основного типа битовой маски.

Количество битов в битовой маске устанавливает предел диапазона значений, которые она может содержать:

#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; по-прежнему будет содержать значения от 0 до 255. Дополнительные биты являются битами_заполнения.

Поскольку битовые маски не обязательно начинаются с начала байта, адрес битовой маски нельзя получить. Указатели и ссылки на неконстантные битовые маски недопустимы. При инициализации константной ссылки из битовой маски создаётся временный объект (его тип — тип битовой маски), копируемый по значению из битовой маски, и ссылка привязывается к этому временному объекту.

Для битовых масок нет инициализаторов_членов_по_умолчанию: 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 размер поля битовой маски не может превышать размер базового типа, и то, являются ли int битовые маски, которые не явно signed или unsigned знаковыми или беззнаковыми, определяется реализацией. Например, int b:3; может иметь диапазон значений 0..7 или -4..3 в C, но только последнее значение допустимо в C++.

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

Отчёт об ошибке Применено к Поведение, опубликованное Корректное поведение
CWG 324 C++98 не было указано, является ли возвращаемое значение
присваивания в битовое поле битовым полем
добавлены спецификации битовых полей для
операторов, которые могут возвращать lvalue
CWG 739 C++98 знаковость битовых полей, которые не объявлены
signed ни unsigned была определена реализацией
соответствует типам базового уровня
CWG 2229 C++98 безымянные битовые поля могли быть объявлены с типом с квалификаторами cv запрещено
CWG 2511 C++98 квалификаторы cv не допускались в типах битовых полей битовые поля могут иметь типы перечислений с квалификаторами cv

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2023):
    • 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]

См. также

bitset
реализует массив битов постоянной длины
(шаблон класса)
vector<bool>
эффективная с точки зрения памяти динамическая битовая маска
(специализация шаблона класса)
Работа с битами (C++20) инструменты для доступа, изменения и обработки отдельных битов и последовательностей битов
Документация C для Битовых полей

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/bit_field

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API