Влияние __attribute __ ((упаковано)) на вложенный массив структур?

Проблема

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

typedef struct __attribute__((packed))
{
   uint16_t field1;
   uint16_t field2;
   uint16_t field3;
} packed_1_s;

typedef struct __attribute__((packed))
{
   uint16_t fieldA;
   uint16_t fieldB;
   packed_1_s structArray[10];
} packed_2_s;

typedef struct __attribute__((packed))
{
   uint16_t fieldX;
   packed_2_s fieldY;
   uint8_t arrayZ[20];
} data_s;

Я понимаю, что обычно структура Pack_1_s может иметь дополнительное пространство, выделенное для каждого экземпляра структуры, чтобы заполнить ее до предпочтительного размера компилятора (в зависимости от оборудования, для которого она создается), и этот предпочтительный размер может быть от 2 до 64 байтов (последний раз).Обычно, если бы у меня был один экземпляр pack_1_s в пакете_2_s, проблем не было бы, но я понимаю, что есть некоторые различия, когда вы пытаетесь поместить элементы в массив.

Попытки решения

Похоже, что документация gcc предполагает, что при простом включении атрибута pack в определение Packed_2_s поля, даже если они являются массивами, будут максимально плотно упакованы и не будут добавлять места. в структуру pack_2_s для выравнивания элементов массива. Однако документация по атрибуту align () предполагает, что массивы обрабатываются иначе, чем другие поля, и что для него необходим атрибут align / Packaging, установленный непосредственно в поле, чтобы он мог изменять добавленный дополнительный интервал для соответствия указанному выравниванию (или его отсутствию). Я попытался установить упакованный атрибут в поле structArray, и когда это не сработало, провел тест, установив упакованный атрибут в arrayZ в приведенном выше коде:

packed_1_s structArray[10] __attribute__((packed));

uint8_t arrayZ[20] __attribute__((packed));

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

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

Соображения

Из того, что я могу определить из документации GCC, похоже, что есть 3 основных случая вставки дополнительной памяти.

  1. Содержимое структуры может иметь дополнительную память, выделенную самой структуре , чтобы изменять интервал между полями.
    Фактически, определение карты памяти структуры содержимого внутри структуры может измениться (но не порядок элементов).
  2. У структур может быть выделена дополнительная память, чтобы заполнить их до более эффективного общего размера. Обычно это предназначено для того, чтобы другие переменные, следующие после объявления одного из их экземпляров, не попадали в тот же «блок», что и экземпляр структуры , где «блок» определяется системой / компилятором.
  3. Массивы, независимо от того, находятся они внутри структуры или нет, могут иметь дополнительную память, добавленную к ним, чтобы сдвинуть элементы для эффективного выравнивания.

Насколько я могу судить, атрибут Packaging можно использовать для воздействия на структуры и блокировки дополнительной памяти, добавленной в случаях 1 и 2 выше, но, похоже, нет способа обработать случай 3 выше на моем компилятор (ы).

Вопрос

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

РЕДАКТИРОВАТЬ

Я обсуждал некоторые проблемы с моим местным гуру, и похоже, что я неправильно понимаю случай 3 выше. Между элементами в массиве нет места, но дополнительное пространство, чтобы гарантировать, что они правильно выровнены, добавляется к самой структуре.По-видимому, это предполагает, что такие вещи, как «sizeof (structureOnlyContain_uint32_t)», не всегда будут возвращать «4», поскольку может быть добавлено дополнительное пространство для выравнивания типа данных uint32_t на используемом компиляторе. В результате реально всего 2 случая:

  1. Большие смещения между полями в карте памяти структуры.
    Расстояние между полями можно изменить, чтобы выровнять каждое поле. Это можно изменить с помощью атрибутов pack или align ().
  2. Заполнение конца структуры. Размер структуры, возвращаемый функцией sizeof (), может быть изменен таким образом, чтобы массивы структур в конечном итоге были правильно выровнены для системы. Это позволяет всем системам предполагать , что начало структур всегда будет выровнено, вызывая проблемы , если это не так. Кажется, это не зависит от атрибутов pack или align.

В связи с новым случаем 2 элементы массива в структуре не обязательно подчиняются атрибутам pack или align (), указанным в структуре, хотя начало массива и поле, следующее сразу за массивом, подчиняются.

Тогда у меня вопрос о том, как работать с structArray в упакованном_2_s, поскольку размер массива в целом не может быть гарантирован только атрибутом упакованного. Есть ли способ гарантировать фиксированный размер поля structArray в целом? Следует отметить, что я не могу слишком сильно увеличивать размер pack_1_s, поскольку структура data_s должна быть как можно меньше (она заменяет данные Audio / Video в сценарии потоковой передачи).

16
задан emlai 25 June 2015 в 15:59
поделиться