Подтвердить что ты не робот

Можно ли использовать перечисление в поле бит?

Скажем, у меня есть следующая структура:

typedef struct my_struct{
    unsigned long       a;
    unsigned long       b;
    char*               c;
    unsigned int        d1  :1;
    unsigned int        d2  :4;
    unsigned int        d3  :4;
    unsigned int        d4  :23;
} my_type, *p_type;

В настоящее время поле d3 определяется #define, которое достигает от 0x00 до 0x0D.

Собственно, d3 - это перечисление. Так что соблазнительно пойти и заменить

    unsigned int        d3  :4;

по

    my_enum             d3  :4;

Это безопасно/разрешено?

Код должен компилироваться с различными

  • компиляторы (GCC, Visual Studio, встроенные материалы)
  • платформы (Win32, Linux, встроенные материалы)
  • конфигурации (скомпилировать как C, скомпилировать как С++)

Очевидно, я мог оставить определение d3 как есть и использовать перечисление в моем коде, назначить его d3 и т.д., но это не сработает с С++.

4b9b3361

Ответ 1

Ответ будет другим для C и С++, это один для C.

В C битполя ограничены signed int, unsigned int, _Bool и int, которые в этом контексте могут быть любыми из первых двух. Разработчики компилятора могут добавить в этот список по своему вкусу, но они должны документировать типы, которые они поддерживают.

Итак, чтобы ответить на ваш вопрос, если вы хотите быть абсолютно уверены, что ваш код переносится ко всем компиляторам C, нет, использование типа enum не является вариантом.

Соответствующий параграф из текущего стандарта гласит:

Поле бит должно иметь тип, который является квалифицированным или неквалифицированным версия _Bool, подписанная      int, unsigned int или какой-либо другой тип реализации. это       реализация - определяется, разрешены ли атомарные типы.

Ответ 2

Это разрешено во всех компиляторах С++, поддерживающих стандартные.

С++ 03 стандарт 9.6/3

Битовое поле должно иметь интегральный или перечисляемый тип (3.9.1). это реализация - определяется, является ли простая (ни явно подписанная, ни беззнаковая) char, short, int или длинное битовое поле подписано или без знака.

С++ 03 стандарт 9.6/4

Если значение enu- merator хранится в бит-поле того же типа перечисления, и количество бит в битовом поле велико достаточно, чтобы удерживать все значения этого типа перечисления, исходное значение счетчика и значение битового поля сравниваются равными.

Пример

enum BOOL { f=0, t=1 };
struct A {
BOOL b:1;
};
A a;
void f() {
a.b = t;
if (a.b == t) // shall yield true
{ /* ... */ }
}

Но вы не можете считать, что перечисление имеет неподписанный базовый тип.

С++ 03 стандарт 7.2/5

Основной тип перечисления является интегральным типом, который может представлять все значения счетчика определенных в перечислении. Определяется реализация, который является интегральным типом в качестве базового типа для перечисления, за исключением того, что базовый тип не должен быть больше, чем int, если значение enu- merator не может поместиться в int или unsigned int

Ответ 3

Нет.

Бит-поля реализованы существенно по-разному между компиляторами. Если вы определяете бит-поле с двумя значениями, ноль и один, и попробуйте ввести поле бит с перечислением, вы можете столкнуться с этими проблемами:

Поле бит будет неподписанным с gcc и clang, но будет подписано с VС++. Это означает, что для хранения нуля и одного вам нужно битовое битовое поле (однобитовое разрядное битовое поле может хранить только ноль и отрицательный).

Тогда вам придется беспокоиться о упаковке. VС++ будет только упаковывать соседние битовые поля в один и тот же хранилище, если их размеры совпадают. Я не уверен, что такое правила для gcc и clang, но для VС++ хранилище резервных копий по умолчанию для битового поля является int. Таким образом, ряд бит-полей, которые представляют собой, например, смесь bool и enum, будет очень плохо упаковываться с помощью VС++.

Вы можете попытаться решить эту проблему с помощью типизированных перечислений на С++ 11:

enum Foo: unsigned char {one, two};

но затем gcc жалуется, если вы используете это в однобитовом битовом поле:

warning: 'bitfieldTest:: g слишком мал, чтобы сохранить все значения enum Foo [включено по умолчанию]

Кажется, победа не существует.

Ответ 4

В C это поведение undefined, потому что бит-поле может иметь только типы signed int, int или unsigned int (или _Bool с C99).

6.5.2.1:

Поле бит должно иметь тип, который является квалифицированным или неквалифицированным версию одного из int, unsigned int или signed int. Является ли старшая позиция бит (возможно, квалифицированная) "plain" int бит-поле рассматривается как знаковый бит, определяется реализацией. битовое поле интерпретируется как интегральный тип, состоящий из указанное количество бит.

В противном случае некоторые компиляторы принимают его сегодня как расширение (например, поведение, определяемое реализацией расширений в стандарте).