次のページ 前のページ 目次へ

5. パディング

パディングとは,アラインメント条件を満たすために構造体に勝手に入っ てしまう「詰めもの」のことです. これもアラインメントと同様,RISC アーキテクチャのプロセッサでは一般的 な話題です.

5.1

パディング自体は x86 でも生じます. が,以下のプログラムは,x86 と ARM でパディングの挙動が異なる例です.


#include <stdio.h>

struct s0 {
        unsigned char a, b, c;
};

struct s1 {
        char d;
        struct s0 e;
};


main ( void )
{
        struct s1 s;
        void *s_a = (void *)&s,
                *d_a = (void *)&s.d,
                *e_a = (void *)&s.e;
        
        printf ( "d = %d\n", d_a - s_a );
        printf ( "e = %d\n", e_a - s_a );
}

このプログラムの x86 での実行結果を以下に示します.

$ ./a.out 
d = 0
e = 1

ARM での実行結果は以下のようになります.

$ ./a.out 
d = 0
e = 4

5.2 由緒正しい対策

やはり

「パディングに依存しないプログラムを書く」
というのが正しい対策でしょう.

特に,データストリームに対して構造体のポインタを設定し,直接値を読み取 る,というようなプログラムは書くべきではないでしょう.

5.3 バッドノウハウな対策

構造体の宣言に gcc 拡張の __attribute__ ((packed)) の属性を付ける ことによって,パディングを抑止することができます.


#include <stdio.h>

struct s0 {
        char a, b, c;
} __attribute__ ((packed));

struct s1 {
        char d;
        struct s0 e;
} __attribute__ ((packed));


main ( void )
{
        struct s1 s;
        void *s_a = (void *)&s,
                *d_a = (void *)&s.d,
                *e_a = (void *)&s.e;
        
        printf ( "d = %d\n", d_a - s_a );
        printf ( "e = %d\n", e_a - s_a );
}

このプログラムを ARM 上で実行すると

$ ./a.out 
d = 0
e = 1
と,x86 と同様の結果が得られます.

ただし,x86 で付くはずのパディングまで削除してしまうので,使用には注意 が必要です. が,「x86 環境とと同一の実行結果を得る」という目的は達することができる でしょう.


次のページ 前のページ 目次へ