Принудительная усадка битового поля в MSVC

У меня есть структура битовых полей, которые содержат до 48 бит. В GCC это правильно приводит к 6-байтовой структуре, но в MSVC структура выходит из 8 байтов. Мне нужно найти способ заставить MSVC правильно упаковать структуру, как для интероперабельности, так и потому, что она используется в критически важной для среды среде.

Структура, представленная ниже, состоит из трех 15-битных чисел, одного 2-битного числа и 1-битного знака. 15 + 15 + 15 + 2 + 1 = 48, поэтому теоретически он должен входить в шесть байтов, верно?

struct S
{
  unsigned short a:15;
  unsigned short b:15;
  unsigned short c:15;
  unsigned short d:2;
  unsigned short e:1;       
};

Однако, компиляция этого как на GCC, так и на MSVC приводит к sizeof(S) == 8. Думая, что это может иметь отношение к выравниванию, я попытался использовать #pragma pack(1) перед объявлением структуры, сообщая компилятору о возврате в байты, а не int, границы. В GCC это сработало, в результате получилось sizeof(S) == 6.

Однако на MSVC05 размерof все равно вышел на 8, даже с pack(1) установлен! Прочитав этот другой ответ SO, я попытался заменить unsigned short d на unsigned char и unsigned short e на bool. Результат: sizeof(S) == 7!

Я обнаружил, что если я разделил d на два однобитовых поля и вклинил их между другими членами, структура, наконец, упакована должным образом.

struct S
{
  unsigned short a:15;
  unsigned short dHi : 1;
  unsigned short b:15;
  unsigned short dLo : 1;
  unsigned short c:15;
  unsigned short e:1;       
};

printf( "%d\n", sizeof(S) ); // "6"

Но с тем, что я так раскололся, это громоздко и вызывает проблемы для меня позже, когда я должен работать над структурой. Есть ли способ заставить MSVC упаковать эту структуру в 6 байтов, точно так же, как GCC?

Ответ 1

Реализация определена как поля будут помещаться в структуру. Visual Studio поместит последовательные битовые поля в базовый тип, если это возможно, и потеряет оставшееся пространство. (Поля бит С++ в VS)

Ответ 2

Если вы используете тип unsigned __int64 для объявления всех элементов структуры, вы получите объект с sizeof (S) = 8, но последние два байта не будут использоваться, а первые шесть будут содержать данные в нужном формате.

В качестве альтернативы, если вы можете принять некоторое переупорядочение структуры, это будет работать

#pragma pack(1)
struct S3
{
  unsigned int a:15;
  unsigned int b:15;
  unsigned int d:2;
  unsigned short c:15;
  unsigned short e:1;       
};

Ответ 3

Я так не думаю, и я считаю, что поведение MSVC на самом деле правильное, и GCC, который отклоняется от стандарта.

AFAIK, стандарт не позволяет битовым полям пересекать границы слова базового типа.