C ユーザーズガイド

プラグマ

以下の書式を持つ前処理行は、各処理系が定義した処理を指定します。


#pragma <プリプロセッサトークン>

次の #pragma はコンパイルシステムに認識されます。認識されなかったプラグマは無視されます。-v オプションを使用すると、認識されなかったプラグマについて警告が出されます。

#pragma align <整数> (<変数>[,<変数>])

整列プラグマで指定した <変数> のメモリーはデフォルト値によらず、すべて <整数> バイト境界に揃えられます。

#pragma does_not_read_global_data (<関数>[,<関数>])

リストに指定したルーチンが直接にも間接にも大域データを読み取らないことを表明します。この表明により、そうしたルーチンへの呼び出し前後のコードをさらに最適化することができます。具体的には、代入文やストア命令をそうした呼び出しの前後に移動することができます。

このプラグマは、指定した関数のプロトタイプを宣言した後でのみ使用できます。大域アクセスに関する表明が真でない場合は、プログラムの動作は未定義になります。

#pragma does_not_return(<関数>[,<関数>])

指定した関数への呼び出しが復帰しないことをコンパイラのバックエンドに表明します。この表明により、オプティマイザは、指定された関数への呼び出しが戻らないと仮定して最適化を行うことができます。たとえば、レジスタの存続期間が呼び出し元で終了する場合は、さらに最適化率を高めることができます。

指定した関数が復帰した場合は、プログラムの動作は未定義になります。

次の例に示すように、このプラグマは、指定した関数のプロトタイプを宣言した後でのみ使用できます。


extern void exit(int);
#pragma does_note_return(exit);

extern void __assert(int);
#pragma does_not_return(__assert);

#pragma does_not_write_global_data(<関数>[,<関数>])

リストに指定したルーチンが直接にも間接にも大域データを書き込まないことを表明します。この表明により、そうしたルーチンへの呼び出し前後のコードをさらに最適化することができます。具体的には、代入文やストア命令をそうした呼び出しの前後に移動することができます。

このプラグマは、指定した関数のプロトタイプを宣言した後でのみ使用できます。大域アクセスに関する表明が真でない場合は、プログラムの動作は未定義になります。

#pragma error_messages(on|off|default,<タグ>... <タグ>)

このエラーメッセージプラグマは、ソースプログラムの中から、C コンパイラおよび lint が発行するメッセージを制御可能にします。C コンパイラでは、警告メッセージに対してのみ有効です。C コンパイラの -w オプションを使用すると、このプラグマは無効になり、すべての警告メッセージが抑止されます。

#pragma fini (<関数 1> [,<関数 2>...,<関数 n>])

main() ルーチンを呼び出した後、<関数 1> から <関数 n> までの関数 (終了関数) を呼び出します。この種の関数は、型が void で引数はあってはなりません。プログラム制御下でプログラムが終了したとき、またはこのプログラムを含む共有オブジェクトがメモリーから除去されたときに呼び出されます。次の「初期化関数」の場合と同様、終了関数もリンクエディタによって処理された順に実行されます。

#pragma ident <文字列>

実行可能プログラムの .comment セクション内に任意の <文字列> を格納します。

#pragma init (<関数 1> [,<関数 2>...,<関数 n>])

main() を呼び出す前に、<関数 1> から <関数 n> までの関数 (初期化関数) を呼び出します。この種の関数は、型が void で引数はあってはなりません。実行開始時にプログラムのメモリーイメージを構成しているときに呼び出されます。共有オブジェクトの中の初期値設定子は、その共有オブジェクトをメモリー内へ持っていく動作の間、つまりプログラムの開始中、または dlopen() のような動的ロード動作中に実行されます。初期化関数の呼び出しを順序付ける方法は、それがリンクエディタによって動的または静的に処理される順序に依存します。

#pragma inline(関数[,関数])

指定したルーチン名のインライン化を制御します。このプラグマはファイル全体に対して有効です。このプラグマでは、大域的なインライン化のみ制御可能であり、呼び出し元固有の制御を行うことはできません。

このプラグマは、現在のファイル内にある、指定したルーチンに一致する呼び出しをインライン化するようコンパイラに提案します。この提案は、無視されることがあります。たとえば、関数本体が別のモジュールに存在していて、-xcrossfile オプションが使用されていない場合などです。

次の例に示すように、このプラグマは、指定した関数のプロトタイプを宣言した後でのみ使用できます。


static void foo(int);
static int bar(int, char *);
#pragma inline_routines(foo, bar);

#pragma int_to_unsigned (<関数>)

-Xt モードまたは -Xs モードで unsigned の型を返す <関数> が、戻り値の型 int を持つように変更します。

(SPARC) #pragma MP serial_loop

詳細については 「直列プラグマ」を参照してください。

(SPARC) #pragma MP serial_loop_nested

詳細については 「直列プラグマ」を参照してください。

(SPARC) #pragma MP taskloop

詳細については 「並列プラグマ」を参照してください。

#pragma no_inline(<関数>[,<関数>])

指定したルーチン名のインライン化を制御します。このプラグマはファイル全体に対して有効です。このプラグマでは、大域的なインライン化のみ制御可能であり、呼び出し元固有の制御を行うことはできません。

このプラグマは、現在のファイル内にある、指定したルーチンに一致する呼び出しをインライン化しないようコンパイラに提案します。

このプラグマは、指定した関数のプロトタイプを宣言した後でのみ使用できます。

(SPARC) #pragma nomemorydepend

ループのどの繰り返しでもメモリーの依存がないと指示します。つまり、ループのどの繰り返しの中でも、同じメモリーの参照は必要がないと指示します。このプラグマを指定すると、コンパイラ (パイプライナ) はループの 1 回の繰り返しの中で、より効率的に命令をスケジュールすることができます。ループの繰り返しの中でメモリーの依存があると、プログラムの実行結果は未定義になります。プラグマは現行ブロック内の次の for ループに適用されます。コンパイラはこの情報をレベル 3 以上の最適化に利用します。

(SPARC) #pragma no_side_effect (<関数>)

<関数> は、現行の翻訳単位内の関数名を指定します。関数はプラグマより前に宣言されていなければなりません。またプラグマはその関数の定義より前に指定されていなければなりません。指定した関数 <関数> に対し、プラグマはその関数に一切の副作用がないことを宣言します。コンパイラはこの情報を、その関数を用いる最適化に利用することができます。関数に副作用があると、この関数を呼び出すプログラムの実行結果 は未定義になります。コンパイラはこの情報をレベル 3 以上の最適化に利用します。

#pragma opt_level(<関数>[,<関数>])

指定した関数サブプログラムに対する最適化レベルを指定します。最適化レベルとしては 0〜5 を選択することができます。0 に設定すると、最適化は無効になります。このプラグマを使用する前に、関数サブプログラムのプロトタイプを作成しておく必要があります。

#pragma pack(n)

構造体のメンバーの境界整列を制御します。デフォルトでは、構造体のメンバーは、char 型なら 1 バイト、short 型なら 2 バイト、整数なら 4 バイトというように、その自然境界で整列させられます。n を指定する場合には、ゼロもしくはすべての構造体メンバーに対して最も厳密な自然境界整列となる 2 の乗数にします。

このプラグマを使用すると、構造体メンバーの境界整列をデフォルトとは異なるものにすることができます。たとえば、#pragma pack(2) を指定すると、intlonglong longfloatdoublelong doublepointer が、それぞれの自然境界ではなく、2 バイト境界に整列されます。

n がプラットフォームで最も厳密な整列を指示する値 (Intel では 4、SPARC v8 では 8、SPARC v9 では 16) か、それより大きな値の場合は、自然境界整列が有効になります。n が省略された場合も、メンバーは自然境界整列に戻ります。

#pragma pack(n) 指令は、その指令から次の #pragma pack 指令の間のすべての構造体の定義に適用されます。別の翻訳単位で同じ構造体に対して異なる #pragma pack の定義が行われている場合、プログラムは予期しない形でコンパイルに失敗することがあります。特に、#pragma pack(n) は、事前にコンパイルされたライブラリのインタフェースを定義するヘッダーをインクルードする前には使用しないでください。#pragma pack(n) は、プログラムコード内の境界整列を変更するすべての構造体の直前に挿入することをお勧めします。そして、その構造体の直後に #pragma pack() を続けてください。

(SPARC) #pragma pipeloop(n)

このプラグマは、引数 n に正の整定数または 0 を受け入れます。このプラグマは、ループがパイプライン化可能で、ループによる依存の最小の依存距離が n であることを指定します。距離が 0 の場合、そのループは実質的には Fortran 形式の doall ループで、ターゲットプロセッサ上でパイプライン処理するべきであることを意味します。距離が 0 より大きい場合、コンパイラは n 回だけの連続繰り返しでパイプラインを試みます。プラグマは現行ブロック内の次の for ループに適用されます。コンパイラはこの情報をレベル 3 以上の最適化に利用します。

#pragma rarely_called(<関数>[,<関数>])

指定した関数があまり使用されないというヒントをコンパイラのバックエンドに与えます。このヒントにより、コンパイラは、プロファイル収集段階に負担をかけることなく、ルーチンの呼び出し元でプロファイルフィードバック方式の最適化を行うことができます。このプラグマは提案ですので、コンパイラのオプティマイザは、このプラグマに基づく最適化を行わないこともあります。

次の例に示すように、#pragma rarely_called プリプロセッサ指令は、指定した関数のプロトタイプを宣言した後でのみ使用できます。


extern void error (char *message);
#pragma rarely_called(error);

#pragma redefine_extname <旧外部参照名> <新外部参照名>

このプラグマにより、オブジェクトコード中で外部定義された <旧外部参照名> の名前がすべて <新外部参照名> に置換されます。この結果、リンク時にリンカーは新しい名前だけを認識します。関数定義、初期設定子、または式のいずれかとして <旧外部参照名> を最初に使用した後、#pragma redefine_extname が指定されていると、結果は未定義になります (-Xs のモードではこのプラグマはサポートされていません)。

#pragma redefine_extname を使用できる場合、コンパイラは、事前に定義されたマクロの PRAGMA_REDEFINE_EXTNAME の定義を使用して、#pragma redefine_extname の有無に関係なく機能する移植可能なコードを作成できるようにします。

#pragma redefine_extname の目的は、関数名を変更できない場合に関数インタフェースを効率的に再定義する手段を提供することにあります。関数名を変更できない場合とは、たとえば、既存のプログラムとの互換性を保つために、ライブラリ内に、関数の古い定義と (新しいプログラムで使用する) 新しい定義の両方を維持する必要がある場合です。ライブラリに新しい名前で新しい関数定義を追加した場合に、このようなことが必要になります。新旧の名前と定義が存在する関数を宣言するヘッダーファイルで #pragma redefine_extname を使用すると、その関数が使用されるときは、必ずその関数の新しい定義でリンクされるようになります。


#if    defined(__STDC__)

#ifdef __PRAGMA_REDEFINE_EXTNAME
extern int myroutine(const long *, int *);
#pragma redefine_extname myroutine __fixed_myroutine
#else /* __PRAGMA_REDEFINE_EXTNAME */

static int
myroutine(const long * arg1, int * arg2)
{
    extern int __myroutine(const long *, int*);
    return (__myroutine(arg1, arg2));
}
#endif /* __PRAGMA_REDEFINE_EXTNAME */

#else /* __STDC__ */

#ifdef __PRAGMA_REDEFINE_EXTNAME
extern int myroutine();
#pragma redefine_extnmae myroutine __fixed_myroutine
#else /* __PRAGMA_REDEFINE_EXTNAME */

static int
myroutine(arg1, arg2)
    long *arg1;
    int *arg2;
{
    extern int __fixed_myroutine();
    return (__fixed_myroutine(arg1, arg2));
}
#endif /* __PRAGMA_REDEFINE_EXTNAME */

#endif /* __STDC__ */

#pragma returns_new_memory(<関数>[,<関数>])

指定した関数の戻り値が呼び出し元のどのメモリーとも別名処理されないことを表明します。つまり、この呼び出しでは、新しいメモリー位置が返されます。この表明により、オプティマイザはポインタ値を追跡して、メモリー位置を明確にし、ループのスケジューリングやパイプライン処理、並列化処理を改善することができます。表明が偽の場合には、プログラムの動作は未定義になります。

次の例に示すように、このプラグマは、指定した関数のプロトタイプを宣言した後でのみ使用できます。


void *malloc(unsigned);
#pragma returns_new_memory(malloc);

#pragma unknown_control_flow (<名前> [,<名前>]...)

通常の手続き呼び出しの制御フロー特性に反するルーチンのリスト <名前> [,<名前>]... を指定します。たとえば setjmp() の呼び出しの後ろに置かれた文は、他のルーチンに対する任意の呼び出しから到達できます。この文は longjmp() の呼び出しで到達されます。このようなルーチンは標準のフローグラフ解析を無効にしますので、それらを呼び出すルーチンは安全に最適化できません。したがって、それらはオプティマイザを抑止してコンパイルされます。

(SPARC) #pragma unroll (<展開係数>)

このプラグマは、引数 <展開係数> に正の整定数を受け入れます。プラグマは現行ブロック内の次の for ループに適用されます。展開係数が 1 以外の場合、指定されたループを指定の係数で展開するよう、コンパイラに指示します 。コンパイラは可能な限り、その展開係数を使用します。展開係数が 1 の場合、ループを展開してはならないことをコンパイラに指定します。コンパイラはこの情報をレベル 3 以上の最適化に利用します。

#pragma weak <シンボル 1> [=<シンボル 2>]

弱い大域シンボルを定義します。このプラグマは主にライブラリを構築するソースファイルの中で使用されます。リンカーは弱いシンボルを解決できなくてもエラーメッセージを表示しません。


#pragma weak <シンボル>

これは <シンボル> を弱いシンボルとして定義しています。<シンボル> の定義が見つからなくても、リンカーはメッセージ等を出さなくなります。


#pragma weak <シンボル 1> = <シンボル 2>

これは <シンボル 1> を、<シンボル 2> の別名の弱いシンボルと定義します。この形式のプラグマは、ソースファイルまたはそこにインクルードされたヘッダーファイルのいずれかで、<シンボル 2> を定義した同じ変換ユニットの中に限り使用できます。それ以外で使用された場合は、コンパイルエラーになります。

プログラムが <シンボル 1> を呼び出しますが、それがプログラム中で定義されていない場合には、<シンボル 1> がリンクライブラリ中の弱いシンボルになっていると、リンカーはライブラリにある定義を使用します。しかし、プログラム自身が <シンボル 1> を定義してある場合、プログラムでの定義が優先され、ライブラリに存在する <シンボル 1> の弱い大域定義は使用されません。プログラムが直接 <シンボル 2> を呼び出すと、ライブラリにある定義が使用されます。<シンボル 2> の定義が重複して行われるとエラーになります。