Что такое "упакованная" структура в C? - PullRequest
29 голосов
/ 29 марта 2011

Я собираюсь написать код C, написанный для компилятора Microchip C30, и часто вижу структуры, определенные следующим образом:

typedef struct __attribute__((__packed__)) 
{
    IP_ADDR     MyIPAddr;               // IP address
    IP_ADDR     MyMask;                 // Subnet mask
    IP_ADDR     MyGateway;              // Default Gateway
        // etc...
} APP_CONFIG;

Что означает упакованный код?

Ответы [ 5 ]

61 голосов
/ 29 марта 2011

Когда структуры определены, компилятору разрешается добавлять отступы (пробелы без фактических данных), чтобы члены попадали в границы адресов, которые легче доступны для CPU.

Например, на 32-32-битные члены ЦП должны начинаться с адресов, кратных 4 байтам, для эффективного доступа (чтения и записи).Следующее определение структуры добавляет 16-разрядное заполнение между обоими элементами, так что второй элемент попадает в правильную границу адреса:

struct S {
    int16_t member1;
    int32_t member2;
};

Структура в памяти вышеупомянутой структуры в 32-разрядной архитектуре( ~ = заполнение):

+---------+---------+
| m1 |~~~~|   m2    |
+---------+---------+

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

Та же самая структура, когда она упакована, появится в памяти как-то вроде:

+---------+---------+
| m1 |   m2    |~~~~
+---------+---------+
6 голосов
/ 29 марта 2011

Указывает компилятору не добавлять никаких отступов между элементами struct.

См., Например, эта страница .

1 голос
/ 30 апреля 2019

Одна вещь, которая не была явно вызвана, состоит в том, что упаковка обычно выполняется для соответствия предопределенным структурам поля. Например, на низкоуровневом уровне сетевого интерфейса между сетевыми машинами происходит обмен серией байтов. После получения данных их необходимо сопоставить с высокоуровневой структурой, чтобы можно было легко манипулировать данными. Это когда обычно не требуется дополнения, чтобы структура напрямую отображалась в байтах.

Обмен сетевыми данными также связан с проблемой байтовой байтовости (т. Е. Почти все сетевые данные используют формат байтов с прямым порядком байтов, независимо от порядкового номера машин источника и назначения).

Кроме того, некоторые машины не могут получать доступ к широким данным по невыровненному адресу, например, ядра Cortex-M0 не могут получить доступ к 32-разрядным данным по не 32-разрядному выровненному адресу, поэтому необходимо соблюдать осторожность. при написании сетевого кода в таких случаях.

1 голос
/ 28 апреля 2019

Позвольте мне объяснить концепцию заполнения в структурах и затем упакованных структурах на примере.

А затем давайте посмотрим, почему требуется упаковка.

Заполнение:

struct eg_struct
{
           unsigned char abc;
           unsigned int  xyz;
}

Когда структура объявлена, как указано выше для 16-битной архитектуры, переменной abc будет назначен некоторый адрес.Следующий адрес не присваивается переменной xyz, вместо этого добавляется один дополнительный байт, а затем следующий адрес будет присваиваться переменной xyz.

В конце структура выглядит примерно так::

struct eg_struct
{
           unsigned char abc;
           unsigned char paddedbytes[1];
           unsigned int  xyz;
}

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

Упаковка:

Если та же структура объявлена ​​с использованием атрибута «packed», дополнительный байт будетне добавляется после переменной abc.

Позвольте мне привести один пример, где требуется упаковка:

Рассмотрим микроконтроллер, сопряженный с EEPROM, где используется некоторая структурасохранен.

Представьте, что запись функции в EEPROM будет выглядеть следующим образом:

Write_EEPROM(EEPROM address, Ram address, Byte count);

Теперь, если упаковка не выполнена, дополнительные заполненные байты будут занимать пространство в EEPROM, котороебесполезно.

1 голос
/ 29 марта 2011

_attribute__((__packed__)) означает (наиболее вероятно) «не вставляйте какие-либо отступы, чтобы ускорить процесс», а также может означать «не вставлять какие-либо выравнивания для сохранения выравнивания».

...