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

Представьте структуру, состоящую из 32-битных, 16-битных и 8-битных значений элементов. Где порядок значений членов таков, что каждый элемент находится на его естественной границе.

struct Foo
{
    uint32_t a;
    uint16_t b;
    uint8_t c;
    uint8_t d;
    uint32_t e;
};

Правила выравнивания и заполнения элементов документированы для Visual С++. sizeof (Foo) на VС++ указанная выше структура предсказуемо "12".

Теперь я уверен, что правило состоит в том, что не следует делать предположения о заполнении и выравнивании, но на практике, делают ли другие компиляторы в других операционных системах аналогичные гарантии?

Если нет, есть ли эквивалент "#pragma pack (1)" на GCC?

Ответ 1

В системах, которые действительно предлагают эти типы, он, скорее всего, будет работать. Например, в 36-битной системе эти типы не будут доступны в первую очередь.

GCC предоставляет атрибут

__attribute__ ((packed))

С аналогичным эффектом.

Ответ 2

В целом вы правы, что это не безопасное предположение, хотя вы часто получаете упаковку, которую вы ожидаете от многих систем. Вы можете использовать атрибут packed для своих типов при использовании gcc.

например.

struct __attribute__((packed)) Blah { /* ... */ };

Ответ 3

На практике, в любой системе, где существуют типы uintXX_t, вы получите желаемое выравнивание без заполнения. Не бросайте уродливые gcc-измы, чтобы попытаться гарантировать это.

Изменить: Чтобы выяснить, почему вредно использовать attribute packed или aligned, это может привести к смещению цельной структуры при использовании в качестве член большей структуры или в стеке. Это, безусловно, повредит производительность, а на компьютерах, отличных от x86, создаст гораздо больший код. Это также означает, что он недействителен для ввода указателя на любой член структуры, поскольку код, который обращается к значению с помощью указателя, не будет знать, что он может быть смещен и, следовательно, может быть неисправен.

Что касается того, почему это лишнее, имейте в виду, что attribute специфичен для компиляторов gcc и gcc-workalike. Стандарт C не оставляет выравнивание undefined или неопределенным. Он реализован, что означает, что реализация требуется для дальнейшего указания и документирования того, как она себя ведет. gcc-поведение всегда и всегда заключалось в выравнивании каждого элемента структуры на следующей границе его естественного выравнивания (такое же выравнивание, которое оно имело бы при использовании вне структуры, что обязательно является числом, которое равномерно делит размер типа), Поскольку attribute является gcc-функцией, если вы его используете, вы уже предполагаете компилятор, подобный gcc, но затем по предположению, что вы уже хотите выполнить выравнивание.