1.2.2. 構造体に含まれる非境界整列フィールド

グローバル変数がデータ自身と同じサイズの境界に配置されるのと同様に、構造体内のフィールドもデータ自身と同じサイズの境界に配置されます。そのため、多くの場合、コンパイラでは、フィールドを境界整列させるために、フィールド間にパディングを挿入する必要があります。コンパイラでは、構造体内のフィールド間にパディングを挿入した場合、以下のような注釈を生成します。

#1301-D: padding inserted in struct mystruct

また、構造体全体が境界整列されるように構造体の最後にパディングを挿入した場合には、以下の注釈を生成します。

#2530-D: padding added to end of struct mystruct

注釈を表示するには、--remarks コンパイラオプションを使用します。

コンパイラによってパディングが挿入されないようにすることもできます。__packed 修飾子を使用すると、フィールド間にパディングが挿入されない構造体が作成され、これらの構造体は、非境界整列アクセスを必要とします。

ARM コンパイラは、特定の構造体のアライメントを検出した場合、アクセスするフィールドがパック構造体内で境界整列されているかどうかを判断できます。このような場合、コンパイラでは、境界整列ワードまたはハーフワードへのアクセスを可能な限り効率的に実行します。効率的なアクセスを実行できない場合、コンパイラでは、複数の境界整列メモリアクセス(LDRSTRLDM、および STM)を特定のシフト命令とマスク命令を組み合わせて使用し、メモリ内の正しいバイトにアクセスします。

非境界整列要素へのアクセスがインラインで行なわれるか、関数呼び出しで行われるかは、-Ospace(デフォルト、関数の呼び出し)および -Otime(非境界整列のアクセスをインラインで実行)コンパイラオプションで制御されます。

以下に例を示します。

  1. 以下のコードを含むファイル foo.c を作成します。

    __packed struct mystruct {
        int aligned_i;
        short aligned_s;
        int unaligned_i;
    };
    struct mystruct S1;
    
    int foo (int a, short b)
    {
        S1.aligned_i=a;
        S1.aligned_s=b;
        return S1.unaligned_i;
    }
    
  2. このファイルを armcc -c -Otime foo.c を使用してコンパイルします。生成されるコードを以下に示します。

    MOV      r2,r0
    LDR      r0,|L1.84|
    MOV      r12,r2,LSR #8
    STRB     r2,[r0,#0]
    STRB     r12,[r0,#1]
    MOV      r12,r2,LSR #16
    STRB     r12,[r0,#2]
    MOV      r12,r2,LSR #24
    STRB     r12,[r0,#3]
    MOV      r12,r1,LSR #8
    STRB     r1,[r0,#4]
    STRB     r12,[r0,#5]
    ADD      r0,r0,#6
    BIC      r3,r0,#3
    AND      r0,r0,#3
    LDMIA    r3,{r3,r12}
    MOV      r0,r0,LSL #3
    MOV      r3,r3,LSR r0
    RSB      r0,r0,#0x20
    ORR      r0,r3,r12,LSL r0
    BX   lr
    

    コンパイラに詳細な情報を渡して、境界整列されるフィールドとされないフィールドを通知することができます。この情報を渡すには、非境界整列フィールドを __packed として宣言し、struct 自体から __packed 属性を削除する必要があります。

    これは推奨される方法であり、struct 内の自然な境界で整列されたメンバに高速にアクセスできる唯一の方法です。

    この方法を使用すると、どのフィールドが非境界整列フィールドであるかもより明確になりますが、struct でフィールドを追加または削除する場合には注意が必要です。

  3. foo.c に含まれる構造体の定義を以下のように変更します。

    struct mystruct {
        int aligned_i;
        short aligned_s;
        __packed int unaligned_i;
    };
    struct mystruct S1;
    
  4. foo.c をコンパイルすると、以下のような効率的なコードが生成されます。

    MOV      r2,r0
    LDR      r0,|L1.32|
    STR      r2,[r0,#0]
    STRH     r1,[r0,#4]
    LDMIB    r0,{r3,r12}
    MOV      r0,r3,LSR #16
    ORR      r0,r0,r12,LSL #16
    BX       lr
    

同じ原則が共用体にもあてはまります。メモリ内で非境界整列される共用体のコンポーネントには、__packed 属性を使用します。

Note

ポインタを介してアクセスされる __packed オブジェクトの場合、パック構造体であっても、そのアライメントは不明です。

Copyright © 2002-2006 ARM Limited. All rights reserved.ARM DUI 0203GJ
Non-Confidential