Подтвердить что ты не робот

Что такое "упакованная" структура в C?

Я собираюсь, хотя некоторый код 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;

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

4b9b3361

Ответ 1

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

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

struct S {
    int16_t member1;
    int32_t member2;
};

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

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

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

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

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

Ответ 2

Он инструктирует компилятор не добавлять никаких дополнений между членами struct.

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

Ответ 3

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

Ответ 4

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

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

Обивка:

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, что бесполезно.

Ответ 5

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

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

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