10.12 __packed

__packed 修飾子は、構造体を外部のデータ構造体にマップしたり、非境界整列データにアクセスしたりする際に使用すると効果的ですが、非境界整列アクセスにかかるコストが比較的高いため、一般的には、データサイズの削減には効果がありません。

使用法

__packed 修飾子を指定すると、すべての有効な型の境界整列が 1 に設定されます。
つまり、以下のことを意味します。
  • パックオブジェクトを境界整列させるためのパディングの挿入は行われません。
  • パック型のオブジェクトの読み出しまたは書き込みは、非境界整列アクセスを使用して行われます。
構造体または共用体が __packed 修飾子を使用して宣言されている場合、そのすべてのメンバに __packed 修飾子が適用されます。メンバ間にも構造体の終わりにもパディングは挿入されません。パック構造体のすべてのサブ構造体は、__packed を使用して宣言する必要があります。非パック構造体の整数サブフィールドは個々にパックできます。
非境界整列アクセスの数は、パックする必要のある構造体にフィールドをパックすることによってのみ減らすことができます。

ハードウェアで非境界整列アクセスをサポートしていない ARM プロセッサ(ARMv6 以前のプロセッサなど)では、コードサイズおよび実行速度において、非境界整列データへのアクセスにコストがかかる場合があります。コードサイズの増大とパフォーマンスの低下を避けるため、パック構造体を介したデータアクセスは最小限に抑える必要があります。

制約条件

__packed を使用する場合は、以下の制限が適用されます。
  • __packed 修飾子は、前に __packed を使用せずに宣言された構造体には使用できません。
  • 他の型修飾子とは異なり、構造体の型については、同じ型について __packed バージョンと __packed 以外のバージョンの両方を使用することはできません。
  • __packed 修飾子は、整数型のローカル変数には影響しません。
  • パック構造体または共用体は、対応する非パック構造体との代入互換性はありません。構造体によって使用されるメモリレイアウトは異なるため、パック構造体を非パック構造体に割り当てるには、フィールドごとにコピーする以外に方法はありません。
  • char 型を除き、__packed を使用しない場合のキャストの影響については定義されていません。非パック構造体をパック構造体にキャストした場合、またはパック構造体をパック構造体にキャストした場合の影響についても定義されていません。非パック整数型へのポインタは、明示的、暗示的を問わず、パック整数型へのポインタに適切にキャストできます。
  • パック配列型はありません。パック配列とは、パック型のオブジェクトの配列を指します。配列はパディングされません。

エラー

__packed 構造体のフィールドまたは __packed で修飾されたフィールドのアドレスを取得すると、 __packed で修飾されたポインタは生成されません。このポインタを非 __packed ポインタに暗黙的にキャストしようとすると、コンパイラによってタイプエラーが生成されます。これは、 #pragma pack を用いた構造体のアドレス取得済みフィールドの動作とは対照的です。

サンプル

このサンプルは、ポインタがパック型を指すことができることを示しています。
typedef __packed int* PpI;          /* pointer to a __packed int */
__packed int *p;                    /* pointer to a __packed int */
PpI p2;                             /* 'p2' has the same type as 'p' */
                                    /* __packed is a qualifier  */
                                    /* like 'const' or 'volatile' */
typedef int *PI;                    /* pointer to int */
__packed PI p3;                     /* a __packed pointer to a normal int */
                                    /*  -- not the same type as 'p' and 'p2' */
int *__packed p4;                   /* 'p4' has the same type as 'p3' */
次のサンプルは、ポインタを使用してパックオブジェクトにアクセスする場合、コンパイラはポインタの境界整列に依存せずに機能するコードを生成することを示しています。
typedef __packed struct
{
    char x;                   // all fields inherit the __packed qualifier
    int y;
} X;                          // 5 byte structure, natural alignment = 1
int f(X *p)
{
    return p->y;              // does an unaligned read
}
typedef struct
{
    short x;
    char y;
    __packed int z;           // only pack this field
    char a;
} Y;                          // 8 byte structure, natural alignment = 2
int g(Y *p)
{
    return p->z + p->x;       // only unaligned read for z
}
関連する概念
5.35 C および C++ コードでの __packed 修飾子と非境界整列型のデータアクセス
5.40 パックされていない struct、__packed struct、個々の __packed フィールドを使用した struct の比較と、__packed struct と #pragma でパックされた struct の比較
関連する参考文書
10.60 __attribute__((packed)) 型属性
10.68 __attribute__((packed)) 変数属性
10.97 #pragma pack(n)
11.4 ARM C および C++ での構造体、共用体、列挙型、ビットフィールド
非機密扱いPDF file icon PDF 版ARM DUI0472LJ
Copyright © 2010-2015 ARM.All rights reserved.