Что означает структурный синтаксис C ++ "a: b" - PullRequest
27 голосов
/ 05 мая 2009

Если у меня есть структура C ++, определяющая 64-битное слово данных, например ..

struct SMyDataWord
{
    int Name : 40;
    int Colour : 24;
};

Что означает синтаксис : 40 ... означает ли это, что первые 40 бит зарезервированы для Имени, а оставшиеся 24 бита для Цвета?

Вот так оно и используется, но раньше я не сталкивался с этим.

Ответы [ 5 ]

20 голосов
/ 05 мая 2009

Битовые поля, перенесенные из C. Name имеет ширину 40 бит, Colour имеет ширину 24 бит. Следовательно, ваша структура имеет как минимум 64 бита. В моей системе 64 бита были бы 8 байтами.

9 голосов
/ 05 мая 2009

Да, это синтаксис для битовых полей . Они обычно используются для определения структур, которые отображаются на аппаратные регистры. Есть некоторые вещи, которые следует иметь в виду, если вы решите их использовать, во-первых, вы не можете знать, как компилятор выполняет компоновку, упорядочивание и заполнение в реальных байтах, составляющих поля, могут и будут различаться у разных компиляторов (и, возможно, с тем же компилятором, но и с другими настройками оптимизации).

6 голосов
/ 05 мая 2009

Это определение битового поля.

Имя - это целое число, которое может хранить ровно 40 бит информации. Цвет может хранить 24 бита.

Это часто делается для того, чтобы сэкономить место в часто используемых структурах или сжать код до размера, который легко обрабатывать для ЦП (в вашем случае 64 бита. Вписывается точно в регистр ЦП на 64-битной машине).

Код, который обращается к битовым полям, будет выполняться чуть медленнее.

3 голосов
/ 08 апреля 2018

Здесь sizeof прекрасно демонстрирует, что происходит под капотом:

#include <iostream>
#include <climits>

struct bc_1 {
   int a : 1;
   int b : 1;
};

struct bc_2 {
   int a : 31;
   int b : 1;
};

struct bc_3 {
   int a : 32;
   int b : 1;
};

struct bc_4 {
   int a : 31;
   int b : 2;
};

struct bc_5 {
   int a : 32;
   int b : 32;
};

struct bc_6 {
   int a : 40;
   int b : 32;
};

struct bc_7 {
   int a : 63;
   int b : 1;
};

int main(int argc, char * argv[]) {
    std::cout << "CHAR_BIT = " << CHAR_BIT;
    std::cout << " => sizeof(int) = " << sizeof(int) << std::endl;

    std::cout << "1,  1:  " << sizeof(struct bc_1) << std::endl;
    std::cout << "31, 1:  " << sizeof(struct bc_2) << std::endl;
    std::cout << "32, 1:  " << sizeof(struct bc_3) << std::endl;
    std::cout << "31, 2:  " << sizeof(struct bc_4) << std::endl;
    std::cout << "32, 32: " << sizeof(struct bc_5) << std::endl;
    std::cout << "40, 32: " << sizeof(struct bc_6) << std::endl;
    std::cout << "63, 1:  " << sizeof(struct bc_7) << std::endl;
}

Дальнейшие действия зависят от вашего компилятора и операционной системы, а также от вашего оборудования В macOS с gcc-7 (с CHAR_BIT = 8 32-битный int (т.е. половина 64-битного long) имеет sizeof(int) = 4), это вывод, который я вижу:

CHAR_BIT = 8 => sizeof(int) = 4
1,  1:  4
31, 1:  4
32, 1:  8
31, 2:  8
32, 32: 8
40, 32: 12
63, 1:  8

Это говорит нам о нескольких вещах: если оба поля типа int помещаются в один int (т. Е. 32 бита в приведенном выше примере), компилятор выделяет только одну int память (bc_1 и bc_2). Как только один int больше не может содержать битовые поля, мы добавляем второе (bc_3 и bc_4). Обратите внимание, что bc_5 на полную мощность.

Интересно, что мы можем «выбрать» больше битов, чем разрешено. Смотри bc_6. Здесь g ++ - 7 выдает предупреждение:

bitfields.cpp::30:13: warning: width of 'bc_6::a' exceeds its type
     int a : 40;
             ^~

Обратите внимание: clang ++ объясняет это более подробно

bitfields.cpp:30:9: warning: width of bit-field 'a' (40 bits) exceeds the width of its type; value will be truncated to 32 bits [-Wbitfield-width]
    int a : 40;
    ^

Однако кажется, что под капотом компилятор выделяет еще одну int память. Или, по крайней мере, он определяет правильный размер. Я предполагаю, что компилятор предупреждает нас, чтобы мы не обращались к этой памяти как int a = bc_6::a (я бы поспорил, что int a будет тогда иметь только первые 32 бита поля bc_6::a ...). Это подтверждается bc_7, общий размер которого равен двум int с, но первое поле охватывает большинство из них.

Наконец, замена int на long в приведенном выше примере ведет себя как ожидалось:

CHAR_BIT = 8 => sizeof(long) = 8
1,  1:  8
31, 1:  8
32, 1:  8
31, 2:  8
32, 32: 8
40, 32: 16
63, 1:  8
3 голосов
/ 05 мая 2009

Используйте их разумно :

Помните, что почти все о битовые поля - это реализация зависимый. Например, биты ли хранятся слева направо или справа налево зависит от фактического аппаратная архитектура. Более того, каждый компилятор использует свой член модель выравнивания, поэтому размер оптимизированного BillingRec 12 байтов, а не 9. Вы не можете взять адрес битового поля, вы не можете создать массивы битов. Наконец, на большинстве реализации использования битовых полей несет на себе скорость над головой. Поэтому, когда Вы оптимизируете свой код, измеряете эффект определенной оптимизации и его компромиссы, прежде чем вы решите использовать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...