[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.30 型の属性の指定

キーワード __attribute__ を使うと、struct 型や union 型を定義するときに、特別な属性を指定することができる。 このキーワードの後ろに、属性の指定を二重括弧に入れて続けておく。 型を定義する際の属性としては、現在三つ定義されている。 alignedpackedtransparent_union である。 これ以外の属性が、関数(see section 関数属性の宣言)や 変数(see section 変数の属性の指定)用に定義されている。

これらのうちの属性は、キーワードの前後に ‘__’ を付加して 指定しても良い。こちらを使うと、同じ名前のマクロがあるかどうか を気にせずにヘッダフィアルの中で使うことができる。 例えば、aligned の代わりに __aligned__ を使っても良い。

属性 alignedtransparent_union は、 typedef 宣言の中か、完全な enum、struct、union 型の 定義 の閉じ中括弧の直後に置くことができる。 属性 packed は、定義の閉じ中括弧の直後にだけ置くことができる。

また、属性を、閉じ括弧の後ろではなくて、 enum、struct、union タグとその型名の間に置くこともできる。

aligned (alignment)

この属性は、指定された型の変数に対し、最小のアラインメントをバイト数で 指定する。例えば、

 
struct S { short f[3]; } __attribute__ ((aligned (8)));
typedef int more_aligned_int __attribute__ ((aligned (8)));

と宣言すると、struct S 型や more_aligned_int 型の 変数がそれぞれ、少なくとも 8 バイト境界に割り当てられ、整列される ことを保証する。SPARC では、struct S 型の変数を全て 8 バイト境界に整列すると、GNU CC が ldd 命令と std 命令 (倍語ロードと倍語ストア)を struct S 型の一つの変数を同じ型の 変数にコピーするのに使うことができ、そのため実行時の効率が改善される。

任意の与えられた struct 型や union 型のアラインメントは ANSI C 規格により、少なくとも、問題の structunion の全ての メンバのアラインメントの最小公倍数の倍数になることが要求されている ことに注意して欲しい。このため、structunion 型の アラインメントを調整するのに、そのメンバのどれか一つに alignment を 属性を付加することで、実質的に行なえることになる。だが、上の例で 説明した書き方の方が、struct 型や union 型全体の アラインメントを調整するための指定としては、より明白で、判りやすく、 読みやすい方法と言える。

前出の例のように、与えられた struct 型や union 型に 対して使って欲しいアラインメントをバイト単位で明示的に指定することが できる。別の方法としては、アラインメント因子を書かずに、 コンパイルのターゲット機種で意味のある最大のアラインメントを その型に指定させるのを、GNU CC に任せることもできる。 例えば、以下のように書いても良い。

 
struct S { short f[3]; } __attribute__ ((aligned));

aligned 属性の指定で、アラインメント因子を書かないと、GCC は、 その型に、読者のコンパイルのターゲットである機種で 任意のデータ型に対して使われる最大のアラインメントを 自動的に設定する。こうすると、コピー操作の効率が良くなることが多い。 GCC は、このようにアラインメントを設定した変数やフィールドとの 間のコピーを行うときに、最大のメモリの塊をコピーする命令を 使うことができるからである。

上の例で、short の大きさがどれも 2 バイトであれば、 struct S 型全体の大きさは 6 バイトになる。 この大きさ以上で、最小の 2 の冪乗は 8 なので、GCC は struct S 型 全体のアラインメントを 8 バイトに設定する。

与えられた型に対し時間効率の良いアラインメントを選択するように GCC に要求し、その型の単独のオブジェクトだけを個々に宣言する こともできるが、GCC の時間優先アラインメントを選択する能力は、 主に適切な(効率良く整列する)型を持つ変数の配列を作ろうとしている 時にしか役に立たない。効率良く整列される型の変数の配列を宣言したり、 使う時は、読者のプログラムは関連する型への ポインタに対するポインタ算術演算(あるいは同じことだが添え字による参照) も行われるだろう。これらのポインタ算術演算に対して GCC が生成するコードは、 効率良く整列される型に対するもののほうが、他の型に対するものより 効率が良くなる。

属性 aligned はアラインメントを増加させるだけだが、 packed を指定すれば減少させることもできる。以下を参照。

aligned 属性の効果は、リンカの持つ制限により限定される 可能性があることに注意してほしい。多くのシステムでは、リンカは ある決まった最大のアラインメントに変数のアラインメントを切り上げる よう調整することしかできない。(リンカによっては、このサポート されている最大のアラインメントが非常に小さいこともある。) 読者のところのリンカが、最大 8 バイトまでしか 変数のアラインメントを取れない場合は、__attribute__aligned(16) を指定しても、8 バイトのアラインメントしか 取れない。詳細については読者のところのリンカのドキュメントを 見て欲しい。

packed

この属性は、enum 型、struct 型、union 型の定義に 付けて、その型を表現するのに最低限必要なメモリを指定する。

この属性を struct 型と union 型に指定するのは、 その構造体や共用体のメンバのそれぞれに packed 属性を 指定するのと同じである。コマンド行で ‘-fshort-enums’ オプションを 指定するのは、全ての enum 型の定義に packed 属性を 指定すると同じである。

この属性は enum の定義の閉じ中括弧の後にしか指定できない。 typedef の中では、その中に enum の定義も含んで いない限り、指定できない。

transparent_union

この属性を union 型の定義に付けると、その共用体型を持つ 関数のパラメータがある場合、その関数への呼出しが特別な 方法で取り扱われる。

第一に、ある透過共用体型に対応する引数は、その共用体のメンバのうちの どの型にでもなりうる。この場合、キャストは不要である。 また、共用体がポインタ型を含んでいれば、対応する引数は ヌルポインタ定数か void ポインタ式になりうる。 共用体が、void ポインタ型を含んでいれば、対応する引数は任意のポインタ式に なりうる。共用体のメンバの型がポインタであれば、それが参照している 型についての const のような修飾子は、保存されなければならない。 これは普通のポインタの変換と同じである。

第二に、その引数は、透過共用体自身の呼出し規約ではなくて、共用体の先頭の メンバの呼出し規約を使って関数に渡される。 その共用体のメンバは全て同じマシン表現にならなければならない。 これは、この引数を正しく渡すために必要である。

透過共用体は、互換性の理由により複数のインターフェースを 持つライブラリ関数のために設計されている。例えば、関数 wait は、 Posix に準拠するためには int * 型の値を受け付けるか、 4.1BSD のインターフェースに準拠するためには union wait * 型の 値を受け付けるかのどちらかでなければならない。wait の仮引数が void * であれば、wait はどちらの種類の引数でも 受付可能になるが、他のどんなポインタ型でも受け付けることになってしまい、 引数型の検査が役に立たなくなってしまう。代わりに、<sys/wait.h> では以下のようにインターフェースを定義しても良い。

 
typedef union
  {
    int *__ip;
    union wait *__up;
  } wait_status_ptr_t __attribute__ ((__transparent_union__));

pid_t wait (wait_status_ptr_t);

このインターフェースでは、int * 型か union wait * 型の 引数を渡すことができる。呼出し規約は int * を使う。 プログラムでは、どちかの型の引数で wait を呼び出すことができる。

 
int w1 () { int w; return wait (&w); }
int w2 () { union wait w; return wait (&w); }

このインターフェースを使った場合、 wait の実装は以下のように なるだろう。

 
pid_t wait (wait_status_ptr_t p)
{
  return waitpid (-1, p.__ip, 0);
}
unused

この属性を型(unionstruct を含む)に指定すると、 この型の変数が使われない可能性があることを意味する。 GNU CC は、この型の変数が何もしないように見えた場合でも、 これらの変数に対しては警告を出さない。 これは、ロックやスレッドのクラスでは良くあることである。 これらの場合、定義はされるが参照はされない。だが、コンストラクタや デストラクタが含まれていて、その中には色々な管理を行なう機能を持つ。

属性を複数指定するには、カンマで区切って全体を二重括弧で囲む。 例えば、‘__attribute__ ((aligned (16), packed))’ とする。


This document was generated using texi2html 1.78.