Квалификатор __packed полезен для содержимого структуры к внешней структуре данных, или для доступа к не выровненным данным. Однако это не всегда целесообразно экономить на памяти с помощью __packed, потому что это приводит к относительно высокой стоимости доступа к не выровненным данным (unaligned access).
Квалификатор __packed устанавливает выравнивание в 1 для любого допустимого типа. В результате получается следующее:
• Не будет вставляться никаких выравнивающих байтов, чтобы выровнять упакованный объект. • Объекты упакованного типа читаются и записываются с помощью не выровненного доступа к памяти (unaligned access).
Квалификатор __packed применяется ко всем членам (полям) структуры (struct) или объединения (union), когда они декларированы с использованием __packed. После этого между ними, или в конце такой упакованной структуры не будет никаких выравнивающих байт. Все вложенные структуры в упакованную структуру должны быть декларированы с использованием __packed. Целочисленные субполя не упакованной структуры можно упаковать индивидуально. Только упаковка отдельных полей структуры, которая требует упаковки, может снизить количество не выровненных обращений.
Примечание: на процессорах ARM, которое не поддерживают аппаратно не выровненный доступ (например pre-ARMv6), доступ к не выровненным данным может быть дорог в контексте размера кода и скорости его выполнения. Доступ к данным через упакованную структуру должен быть минимизирован, чтобы избежать разрастания кода и снижения производительности.
Ограничения __packed. На использование __packed накладываются следующие ограничения:
• Квалификатор __packed не может использоваться в структурах, которые ранее были декларированы без __packed. • В отличие от квалификаторов других типов Вы не можете иметь упакованную (__packed) и не упакованную (без __packed) версии структур одинакового типа. • Квалификатор __packed не влияет на локальные переменные целочисленного типа. • Упакованная структура или объединение не совместима по присваиванию с соответствующей не упакованной структурой. Причина в том, что в памяти они размещены по-разному, и в этом случае существует единственный способ копирования содержимого одной структуры в другую: копирование полей по отдельности. • Эффект от casting (преобразования типа) для __packed объектов не определен, за исключением типов char. Эффект от casting не упакованной структуры в упакованную, или наоборот, также не определен. Указатель на целочисленный тип не упакованного объекта может быть достоверно подвергнут приведению типа (cast), явно или неявно, к указателю на упакованный интегральный тип. • Не существует типов упакованных массивов. Упакованный массив это массив объектов упакованного типа. Здесь в массиве нет выравнивающих элементов.
Ошибки. Взятие адреса поля в __packed структуре, или адрес поля с квалификатором __packed дает указатель, квалифицированный как __packed. Компилятор сгенерирует ошибку типа (type error), если Вы попытаетесь неявно привести тип (cast) этого указателя к не __packed указателю. Это контрастирует с поведением компилятора для взятия адреса полей структуры, упакованной директивой #pragma packed.
[Примеры __packed]
Пример 1. Следующий пример показывает, что указатель может указывать на упакованный тип.
typedef __packed int* PpI; /* указатель на __packed int */
__packed int *p; /* указатель на __packed int */
PpI p2; /* у 'p2' такой же тип, как и у 'p' */
/* __packed это квалификатор, так же 'const' или 'volatile' */
typedef int *PI; /* указатель на int */
__packed PI p3; /* __packed-указатель на обычный int */
/* -- не тот же тип, что и 'p' или 'p2' */
int *__packed p4; /* у 'p4' такой же тип, что и у 'p3' */
Пример 2. Следующий пример показывает, что при обращении к упакованному объекту через указатель компилятор генерирует код, который работает и не зависит от выравнивания указателя.
// Структура из 5 байт, естественное выравнивание = 1:
typedef __packed struct
{
// Все этой структуры поля наследуют квалификатор __packed:
char x;
int y;
} X;
int f(X *p)
{
return p->y; // приведет к не выровненному чтению (unaligned read)
}
// Структура из 8 байт, естественное выравнивание = 2:
typedef struct
{
short x;
char y;
__packed int z; // упаковано только это поле
char a;
} Y;
int g(Y *p)
{
return p->z + p->x; // не выровненное чтение только для z
}
[Ссылки]
1. Keil __packed keyword site:keil.com. 2. Keil: выравнивание адреса переменных. 3. The __packed qualifier and unaligned data access in C and C++ code site:keil.com. 4. Comparisons of an unpacked struct, a __packed struct, and a struct with individually __packed fields, and of a __packed struct and a #pragma packed struct site:keil.com. 5. __attribute__((packed)) type attribute site:keil.com. 6. __attribute__((packed)) variable attribute site:keil.com. 7. #pragma pack(n) site:keil.com. 8. Structures, unions, enumerations, and bitfields in ARM C and C++ site:keil.com. |