Можно ли принудительно устанавливать размер bool равным 1 в структуре C? - PullRequest
2 голосов
/ 15 апреля 2019

У меня есть структура C с 8 логическими переменными, которые я хочу упаковать в 1 байт.

Вот как я определяю структуру:

typedef struct
{
    bool a : 1;
    bool b : 1; 
    bool c : 1; 
    bool d : 1; 
    bool e : 1; 
    bool f : 1; 
    bool g : 1; 
    bool h : 1; 
} test_struct;

Тогда я хотел бы убедиться, что все в порядке, чтобы установить значения:

test_struct my_struct = { 0 };
my_struct.e = true;

... и проведите тестирование так:

if (my_struct.e)
    // do something

Будут ли все компиляторы предоставлять ожидаемый результат, т. Е. Использовать один бит для хранения значений bool?

Ответы [ 3 ]

3 голосов
/ 15 апреля 2019

Использование битового поля bool для хранения нескольких флагов в неизвестных местах памяти фактически является единственным безопасным и переносимым использованием битовых полей.

Будут ли все компиляторы предоставлять ожидаемый результат, т. Е. Использовать один бит для хранения значений bool?

Да. bool / _Bool - это стандартизированный тип для битовых полей, и отправленный вами код гарантированно будет работать одинаково во всех компиляторах.

Однако серьезные проблемы появляются, как только вы начинаете принимать порядок распределения. Например, *(uint8_t*)&my_struct может буквально привести к чему угодно. Вы не можете предположить, где отдельные логические значения оказываются в памяти.

Более безопасный, чистый и переносимый способ - никогда не использовать битовые поля, а использовать побитовые операторы:

#define a (1u << 0)
#define b (1u << 1)
#define c (1u << 2)
...

uint8_t test = 0;

Тогда:

  • Установить один бит: test |= a
  • Очистить один бит: test &= ~a.
  • Проверьте, установлен ли бит test & a.

Для более крупных типов он даже полностью переносим при разных процессорных процессорах.

2 голосов
/ 15 апреля 2019

Согласно C 2018 6.7.2.1 5 битовое поле может иметь тип _Bool:

Битовое поле должно иметь тип, который является квалифицированной или неквалифицированной версией _Bool, signed int, unsigned int или некоторого другого типа, определенного реализацией…

Предполагается, что источник включает <stdbool.h>, bool равен _Bool, поэтому определение структуры в порядке.

Обратите внимание, что это:

test_struct my_struct = { 0 };

инициализирует все именованные элементы структуры нулем. Это результат спецификации инициализаторов; он не имеет никакого отношения к тому, упакованы ли битовые поля в один байт или нет.

Будут ли все компиляторы предоставлять ожидаемый результат, т. Е. Использовать один бит для хранения значений bool?

Да, стандарт C требует, чтобы реализации C упаковывали битовые поля, если они помещаются в адресуемую единицу хранения, которую реализация выбирает для использования в битовых полях, в C 6.7.2.1 11:

… Если остается достаточно места, битовое поле, которое следует сразу за другим битовым полем в структуре, должно быть упаковано в смежные биты того же блока…

Таким образом, если у вас есть последовательные однобитовые битовые поля, которые умещаются в байте (которые должны быть не менее восьми битов), и им не предшествуют другие битовые поля, они должны быть упакованы в один байт.

1 голос
/ 15 апреля 2019

Отдельные члены структуры здесь относятся к одному биту, и большинство компиляторов упаковывают их вместе. Тем не менее, они не обязаны; Также не требуется, чтобы они составляли общий размер структуры 8 битов; хотя, опять же, вы можете ожидать, что это будет иметь место в большинстве комбинаций платформа / компилятор, о которых вы, вероятно, будете заботиться. Код, основанный на этом, будет довольно переносимым, но если вы ищете абсолютную гарантию, вы не найдете его в стандарте C.

...