Проблема
Я работаю над отправкой необработанной структуры по сети в известную программу на другой стороне, но мне нужно беспокоиться о незаметно введенной памяти, используемой для выравнивания структур (рассматриваются другие вопросы, такие как порядок байтов). Я работаю с чем-то вроде:
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 в pack_2_s, проблем не было бы, но я дал понять, что есть некоторые различия, когда вы пытаетесь поместить элементы в массив.
Попытки решения
Документация gcc, по-видимому, предполагает, что при простом включении упакованного атрибута в определение pack_2_s поля, даже если они являются массивами, будут упакованы настолько плотно, насколько это возможно, и не будут добавлять пространство в структуру pack_2_s для выровнять элементы массива. Документация по атрибуту align (), тем не менее, предполагает, что массивы обрабатываются не так, как другие поля, и для них необходимо установить атрибут align / pack непосредственно в поле, чтобы изменить дополнительный интервал, добавленный в соответствии с указанным выравниванием (или его отсутствием). Я попытался установить упакованный атрибут в поле 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 выше на моем компилятор (ы).
Вопрос
Есть ли способ гарантировать, что к структуре data_s не будет добавлено абсолютно никакого дополнительного пространства или какой-либо из его подструктур, поэтому у меня нет зависимых от компилятора сдвигов в карте памяти? Я неправильно понимаю случаи, когда компилятор может вставить пробел для преднамеренного смещения карты памяти?
EDIT
Я обсуждал некоторые вопросы с моим местным гуру, и похоже, что у меня есть какое-то недопонимание в случае 3 выше.Элементам в массиве не вставлено пространство между ними, но дополнительное пространство для гарантии их правильного выравнивания добавляется к самой структуре.Очевидно, это предполагает, что такие вещи, как «sizeof (structureOnlyConisting_uint32_t)», не всегда будут возвращать «4», так как может быть добавлено дополнительное пространство для выравнивания типа данных uint32_t в используемом компиляторе.В результате на самом деле есть только 2 случая:
- Большие смещения между полями в карте памяти структуры.
Пространство между полями может быть изменено для выравнивания каждогополе.Это можно изменить с помощью атрибутов pack или align (). - Заполнение конца структуры.Размер структуры, возвращаемый функцией sizeof (), можно изменить, чтобы массивы структур были правильно выровнены для системы.Это позволяет всем системам предполагать, что начало структур всегда будет выровнено, в противном случае возникают проблемы.Это кажется незатронутым атрибутами pack или align.
Из-за нового случая 2, элементы массива в структуре не обязательно подчиняются атрибутам pack или align (), указанным вструктура, хотя начало массива и поле, следующее непосредственно за массивом, делают.
Мой вопрос тогда о том, как обращаться с structArray в pack_2_s, так как размер массива в целом не может быть гарантирован чистопо упакованному атрибуту.Есть ли способ гарантировать фиксированный размер поля structArray в целом?Следует отметить, что я не могу слишком сильно увеличить размер pack_1_s, поскольку структуру data_s необходимо поддерживать как можно меньше (ее замену аудио / видео данными в сценарии потоковой передачи).