[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
GNU C では、読者のプログラムで呼び出している関数について 一定の宣言を行うと、GNU CC が関数呼出しを最適化したり、読者の コードをさらに注意深く検査することの手助けとなる。
キーワード __attribute__
を使うことにより、宣言を書くときに
特別な属性を指定することができる。このキーワードの後に、二重の括弧で
囲んだ属性の指定を置く。関数に対しては現在 9 個の属性、
noreturn
、const
、format
、
no_instrument_function
、section
、
constructor
、destructor
、unused
、weak
が
定義されている。section
を含むその他の属性は、
変数宣言(see section 変数の属性の指定)や型(see section 型の属性の指定)
に対してサポートされている。
また、各キーワードの前後に ‘__’ を付けた属性を指定しても良い。
これにより、同じ名前のマクロがある可能性を心配することなく、
ヘッダファイルの中でこれらの属性を使うことができる。
例えば、noreturn
の代わりに __noreturn__
を使うことができる。
noreturn
標準ライブラリ関数のうち幾つかは、abort
や exit
の
ように戻ることが不可能な関数がある。GNU CC はこのことを既に知っている。
プログラムの中には、決して戻らない関数を自分で定義することもあるだろう。
読者は、そういう関数を noreturn
と宣言することで、
その事実を GNU CC に知らせることができる。
例えば、以下のように書いたとする。
void fatal () __attribute__ ((noreturn));
void
fatal (…)
{
… /* Print error message. */ …
exit (1);
}
|
キーワード noreturn
を付けると、GNU CC は関数 fatal
が
戻りえないことを想定する。そうすると、fatal
が戻った場合に
何が起きるかを考えることなしに最適化を行うことができる。
これによりちょっとだけ良いコードになる。もっと重要なのは、
変数が初期化されていないという見せ掛けの警告を押さえることができる点に
ある。
呼出し側関数によりセーブされるレジスタが、noreturn
関数を
呼び出す前にリストアされると想定してはいけない。
nonreturn
と指定された関数に void
型以外の戻り値型を
持たせるのは意味がない。
noreturn
属性は、GNU C のバージョン 2.5 以前では実装されていない。
戻ることのない関数を宣言するもう一つの方法は、次のようになる。
この方法は、現在のバージョンでも使えるし、古いバージョンの幾つかでも
使える。
typedef void voidfn (); volatile voidfn fatal; |
const
多くの関数は引数以外の値を見ないし、戻り値以外の値に影響を与えない。
このような関数は、単なる算術演算子と同じように、
共通部分式削除とループ最適化の適用を受ける。
こういう関数は属性 const
を付けて宣言すべきだろう。
例えば、
int square (int) __attribute__ ((const)); |
とすると、架空の関数 square
は、プログラムが示すよりも
呼び出す回数が少なくても安全であることを表す。
const
属性は、GNU のバージョン 2.5 以前では実装されていない。
関数に副作用が無いことを宣言する別の方法としては、以下の方法がある。
これは現在のバージョンと幾つかの古いバージョンで動作する。
typedef int intfn (); extern const intfn square; |
この方法は GNU C++ 2.6.0 以降では使えない。 言語仕様で ‘const’ は、戻り値に付けなければならないからである。
ポインタの引数があり、それにより指し示されるデータを参照している
関数は、const
と宣言してはならないことに注意。
同様に、非 const
関数を呼び出している関数は普通は const
であってはならない。void
型の関数に const
を
付けるのは意味がない。
format (archetype, string-index, first-to-check)
属性 format
は、関数が printf
や scanf
、
strftime
形式の引数を取り、その引数をフォーマット指定文字列に
対して型検査を行うことを指定する。例えば、
extern int my_printf (void *my_object, const char *my_format, ...) __attribute__ ((format (printf, 2, 3))); |
と宣言すると、GNU CC は、my_printf
への呼出しの引数を、
printf
形式のフォーマット指定文字列である引数 my_format
との一貫性について検査を行わせる。
パラメータ archetype は、フォーマット文字列がどのように
解釈されるかを決め、printf
、scanf
、
strftime
のどれかにしないといけない。
パラメータ string-index はどの引数がフォーマット指定文字列の
引数かを指定する(1 から始める)。一方、first-to-check は
フォーマット指定文字列に対して検査を行うべき最初の引数の番号である。
検査に使える引数がない関数(例えば vprintf
)に対しては、
3番目のパラメータをゼロと指定すること。この場合、
フォーマット文字列についてだけ一貫性があるかどうかの検査が行われる。
上の例で言うと、フォーマット文字列 (my_format
) は
関数 my_print
の二番目の引数であり、検査すべき引数は
3番目の引数から始まるので、format
属性の正しいパラメータは
2 と 3 になる。
format
属性を使うと、フォーマット文字列を引数として取る
読者自身の関数を認識して、GNU CC がこれらの関数への呼出しに誤りが
ないかどうか検査させることができる。
GCC は ANSI ライブラリ関数 printf
、fprintf
、
sprintf
、scanf
、fscanf
、sscanf
、strftime
、
vprintf
、vfprintf
、vsprintf
については、
警告を要求したとき(‘-Wformat’ を指定したとき)は、常に
フォーマットを検査するので、ヘッダファイル ‘stdio.h’ を
修正する必要はない。
format_arg (string-index)
format_arg
属性は、関数が、 printf
あるいは scanf
形式の引数を取り、それを変更し(例えば別の言語へ翻訳する)、さらに
printf
あるいは scanf
形式の関数に渡すということを
指定する。例えば、
extern char * my_dgettext (char *my_domain, const char *my_format) __attribute__ ((format_arg (2))); |
と宣言すると、GCC は、結果が printf
、scanf
、
strftime
形式の関数に渡される my_dgettext
への呼出しに
現れる引数を、printf
形式のフォーマット文字列引数 my_format
と比べて、一貫性があるかどうかを検査する。
パラメータ string-index は、どの引数がフォーマット文字列引数 であるかを指定する(1から始まる)。
format-arg
属性を使うと、フォーマット文字列を修正するような
読者自身の関数を認識して、引数が、読者自身の関数の一つへの呼出しである
ような printf
、scanf
、strftime
関数の呼出しを
検査できるようにする。GCC は、gettext
、dgettext
、
dcgettext
を常にこのように取り扱う。
no_instrument_function
‘-finstrument-functions’ を指定すると、プロファイリングを行う 関数への呼出しが、ほとんどのユーザがコンパイルした関数の入り口と 出口に生成される。この属性を指定した関数については、それが行われない。
section ("section-name")
GCC は、普通、生成したコードを text
セクションに置く。
だが、時によっては、追加のセクションが必要になったり、
ある特定の関数を特別なセクションに置く必要が出てくる。
section
属性は、関数を特定のセクションに置くことを指定する。
例えば、
extern void foobar (void) __attribute__ ((section ("bar"))); |
と宣言すると、関数 foobar
は bar
セクションに置かれる。
ファイル形式によっては、勝手にセクションを作ることをサポートしていないので、
section
属性は全てのプラットフォームで使えるわけではない。
あるモジュールの内容全部をある特定のセクションに移したい場合は、
リンカの機能を使うことを考えてみて欲しい。
constructor
destructor
constructor
属性は、指定した関数が、プログラムの実行が
main ()
に入る前に自動的に呼び出されるようにする。
同じように、destructor
属性を指定すると、その関数が、
main ()
が終了した後か exit ()
が呼ばれた後に、
自動的に呼び出されるようにする。これらの属性を指定した関数は、
プログラムの実行の間に暗黙に使われるデータを初期化するのに
使える。
これらの属性は Objective C については現在実装されていない。
unused
この属性は、関数につけると、その関数は使われない可能性があるという ことを表す。GNU CC はこの関数に対して警告を出さないようになる。 GNU C++ は現在、パラメータが C++ で有効でない定義としては、 この属性をサポートしていない。
weak
weak
属性を使うと、それを指定した宣言は、グローバルシンボル
ではなくウィークシンボルとして生成される。これは主に
ユーザコードで上書き可能なライブラリ関数を定義するのに使われるが、
関数でない宣言でも使うことができる。
ウィークシンボルは ELF ターゲットでサポートされている。
GNU アセンブラとリンカを使う場合は a.out ターゲットでもサポートされる。
alias ("target")
alias
属性を指定すると、その宣言は何か別のシンボルの別名として
生成される。別のシンボルはかならず指定しなければならない。
例えば、
void __f () { /* do something */; } void f () __attribute__ ((weak, alias ("__f"))); |
とすると、‘f’ を ‘__f’ のウィークな別名として宣言する。 C++ では、元の名前にはエンコードされた名前を使わなければならない。
全てのターゲット機種でこの属性がサポートされているわけではない。
no_check_memory_usage
‘-fcheck-memory-usage’ を指定すると、サポート・ルーチンの
呼出しがほとんどのメモリアクセスの前に生成され、サポートコードが
使用状況を記録できるようにし、かつ非初期化また未割当のメモリ領域を使ったのを
検知できるようにする。
GCC が正しく扱えないので、asm
文は許されない。
関数にこの属性を付けて宣言すると、その関数に対するメモリ検査コード
を出さないようにし、異なるオプションを使って別個にコンパイルせずとも
asm
文が使えるようになり、さらに、このオプションを使ってコンパイル
しても無限再帰になることなく、望むなら読者自身のサポート
ルーチンを書けるようになる。
regparm (number)
Intel 386 では、regparm
属性を指定すると、number 個の
整数引数を、スタックの代わりにレジスタ EAX、EDX、ECX
で渡すようになる。可変数引数を取る関数は、依然として全部の引数が
スタックで渡される。
stdcall
Intel 386 では、stdcall
属性を指定すると、可変数引数を
取るのでない限り、呼ばれた関数が、引数を渡すのに使われたスタック
をポップすると想定する。
Windows NT 向け PowerPC コンパイラは、現在、stdcall
属性を
無視する。
cdecl
Intel 386 では、cdecl
属性を指定すると、可変数引数を
取るのでない限り、呼びだし側関数が、引数を渡すのに使われたスタック
をポップすると想定する。これは、‘-mrtd’ オプションの効果を
打ち消すのに使える。
Windows NT 向け PowerPC コンパイラは、現在、cdecl
属性を
無視する。
longcall
RS/6000 と PowerPC では、longcall
属性を指定すると
GCC はその関数を常にポインタ経由で呼び出すようにする。
これにより、現在位置から 64 メガバイト(67,108,864バイト)以上
離れた位置にある関数も呼び出せるようになる。
dllimport
PowrPC で Windows NT を稼働している場合、dllimport
属性を
指定すると、GCC は、その関数を、Windows NT dll ライブラリにより設定
される関数ポインタへのグローバルポインタ経由で呼び出す。
このポインタ名は、__imp_
とその関数名を組み合わせて作られる。
dllexport
PowrPC で Windows NT を稼働している場合、dllexport
属性を
指定すると、GCC は、関数ポインタへのグローバルポインタを提供する。
これにより、その関数は dllimport
属性を指定することで
呼び出せるようになる。
このポインタ名は、__imp_
とその関数名を組み合わせて作られる。
exception (except-func [, except-arg])
PowrPC で Windows NT を稼働している場合、exception
属性を
指定すると GCC は、宣言された関数に対し生成される構造化例外テーブルの
エントリを修正する。文字列または識別子 except-func が、
構造化例外テーブルの 3番目のエントリに置かれる。これは、ある関数を
表す。この関数は、例外が発生したときに例外処理機構から呼び出される。
指定されていれば、文字列あるいは識別子 except-arg が、
構造化例外テーブルの4番目のエントリに置かれる。
function_vector
このオプションは、H8/300 と H8/300H において、指定した関数が 関数ベクタを経由して呼び出される必要があることを示すのに使う。 関数ベクタ経由して関数を呼び出すと、コードサイズが小さくなる。 ただし、関数ベクタ大きさに制限があり(H8/300 では最大 128 エントリ、 H8/300H では最大 64 エントリである)、割り込みベクタとスペースを 共有する。
このオプションを正しく動作させるには、GNU binutils バージョン 2.7 以降の GAS と GLD を使わなければならない。
interrupt_handler
このオプションは、H8/300 と H8/300H において、指定した関数が 割り込みハンドラであることを示すのに使う。GCCは、この属性が指定されていると、 割り込みハンドラの中で使うのに適した、関数入り口点と出口点の命令列を 生成する。
eightbit_data
このオプションは、H8/300 と H8/300H において、指定した変数が 8ビットデータセクションに置かれるべきであることを示すのに使う。 GCC は、8ビットデータ領域にあるデータについては、特定の操作に対し より効率の良いコードを生成する。 8ビットデータ領域は、合計 256 バイトのデータに制限されていることに注意。
このオプションを正しく動作させるには、GNU binutils バージョン 2.7 以降の GAS と GLD を使わなければならない。
tiny_data
このオプションは、H8/300 と H8/300H において、指定した変数が 小(tiny)データセクションに置かれるべきであることを示すのに使う。 GCC は、小データ領域にあるデータについてのロードとストアに対し より効率の良いコードを生成する。 小データ領域は、合計32キロバイトよりちょっと下回る大きさに制限されている ことに注意。
interrupt
このオプションは、M32R/D において、指定した関数が 割り込みハンドラであることを示すのに使う。GCCは、この属性が指定されていると、 割り込みハンドラの中で使うのに適した、関数入り口点と出口点の命令列を 生成する。
model (model-name)
このオプションは、M32R/D において、オブジェクトのアドレス可能性と
関数に対して生成されるコードを設定するのに使う。
識別子 model-name は、small
、medium
、large
のうちのどれか一つである。これらはそれぞれコード・モデルを表す。
small モデルオブジェクトは、メモリの下位 16MB に置かれ
(これにより、それらのアドレスは ld24
命令によりロード可能
になる)、bl
命令で呼びだし可能である。
medium モデルオブジェクトは、32ビットアドレス空間のどこに置いても良く
(GCC は、これらのアドレスをロードするのに seth/add3
命令列を
生成する)、bl
命令で呼びだし可能である。
large モデルオブジェクトは、32ビットアドレス空間のどこに置いても良く
(GCC は、これらのアドレスをロードするのに seth/add3
命令列を
生成する)、bl
命令では到達可能でない可能性がある
(GCC は、さらに遅い seth/add3/jl
命令列を生成する)。
複数の属性を一個の宣言の中で指定するには、二重括弧の中にカンマで区切って 並べるか、一つの属性宣言の直後に属性宣言を続けて書けば良い。
__attribute__
機能に反対する人達もいて、代わりにANSI C の
#pragma
を使うべきだと主張している。#pragma
を
使わないのには理由が二つある。
#pragma
コマンドをマクロから生成するのは不可能である。
#pragma
がどんな意味を持つかわからない。
この二つの理由は、#pragma
を使えば良いのではないかと提案されている
ほとんど全てのアプリケーションに対して適用される。
#pragma
は何に対して使っても基本的に誤りなのである。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated
using texi2html 1.78.