Программирование ARM: решение проблем, FAQ Keil: ключевое слово __packed Sat, May 25 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

Keil: ключевое слово __packed Печать
Добавил(а) microsin   

Квалификатор __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.

 

Добавить комментарий


Защитный код
Обновить

Top of Page