Sun Studio 12: C ユーザーズガイド

2.8 プラグマ

次の書式を持つ前処理行は、


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

各処理系が定義した処理を指定します。

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

2.8.1 align

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

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


#pragma align 64 (aninteger, astring, astruct)
int aninteger;
static char astring[256];
struct astruct{int a; char *b;};

2.8.2 c99

#pragma c99("implicit" | " no%implicit")

このプラグマは、暗黙的な関数宣言の診断を制御します。c99 プラグマの値が "implicit" に設定されている場合 (引用符を使用することに注意)、コンパイラが暗黙的な関数宣言を検出すると、警告が生成されます。c99 プラグマの値が "no%implicit" に設定されている場合 (引用符を使用することに注意)、プラグマの値がリセットされるまで、コンパイラは暗黙的な関数宣言をそのまま受け入れます。

-xc99 オプションの値は、このプラグマに影響を与えます。-xc99=all の場合はプラグマが #pragma c99("implicit") に設定され、-xc99=none の場合はプラグマが #pragma c99("no%implicit") に設定されます。

デフォルトでは、このプラグマは c99=("implicit") に設定されます。

2.8.3 does_not_read_global_data

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

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

指定した関数は、このプラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。大域アクセスに関する表明が真でない場合は、プログラムの動作は未定義になります。

2.8.4 does_not_return

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

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

指定した関数が復帰した場合は、プログラムの動作は未定義になります。次の例に示すように、このプラグマは、指定した関数をプロトタイプまたは空のパラメータリストで宣言したあとでのみ使用できます。


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

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

2.8.5 does_not_write_global_data

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

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

指定した関数は、このプラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。大域アクセスに関する表明が真でない場合は、プログラムの動作は未定義になります。

2.8.6 error_messages

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

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

2.8.7 fini

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

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

大域プログラム状態が初期化関数の影響を受ける場合には注意が必要です。たとえばシステムライブラリ初期化関数を使用したときに何が発生するかがインタフェースに明示的に規定されていないかぎり、システムライブラリ初期化関数によって変更される可能性がある errno の値などの大域状態情報をすべて取得し、復元する必要があります。

2.8.8 hdrstop

#pragma hdrstop

同じプリコンパイル済みヘッダーファイルを共有すべき各ソースファイルの活性文字列 (viable prefix) の最後を識別するために、hdrstop プラグマを最後のヘッダーファイルのあとに置く必要があります。たとえば次のファイルがあるとします。


example% cat a.c
#include "a.h"
#include "b.h"
#include "c.h"
#include <stdio.h>
#include "d.h"
.
.
.
example% cat b.h
#include "a.h"
#include "b.h"
#include "c.h"

ソースファイルの活性文字列は c.h で終わっているので、各ファイルの c.h のあとに #pragma hdrstop を挿入します。

#pragma hdrstop は、cc コマンドで指定されるソースファイルの活性文字列の最後にのみ使用できます。#pragma hdrstop をインクルードファイル内に指定しないでください。

2.8.9 ident

#pragma ident <文字列>

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

2.8.10 init

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

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

大域プログラム状態が終了関数の影響を受ける場合には注意が必要です。たとえばシステムライブラリを終了関数として使用したときに発生する事柄は、インタフェースに明示的に規定されていません。そういった情報が無い状態で、終了関数として使われたシステムライブラリが変更した可能性がある errno の値などの大域状態情報をすべて捕捉して、復元する必要があります。

2.8.11 inline

#pragma [no_]inline (<関数>[, <関数>])

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

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

#pragma no_inline は、現在のファイル内にある、指定したルーチンに一致する呼び出しをインライン化しないようコンパイラに指示します。

次の例に示すように、#pragma inline および #pragma no_inline は、関数がプロトタイプまたは空のパラメータリストで宣言されたあとでのみ使用できます。


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

-xldscope-xinline-xO-xcrossfile も参照してください。

2.8.12 int_to_unsigned

#pragma int_to_unsigned (<関数>)

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

2.8.13 MP serial_loop

(SPARC) #pragma MP serial_loop


注 –

Sun 固有の MP プラグマは推奨されず、サポートされません。代わりに、OpenMP 2.5 規格で規定された API をサポートします。標準命令への移植については、『OpenMP API ユーザーズガイド』を参照してください。


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

2.8.14 MP serial_loop_nested

(SPARC) #pragma MP serial_loop_nested


注 –

Sun 固有の MP プラグマは推奨されず、サポートされません。代わりに、OpenMP 2.5 規格で規定された API をサポートします。標準命令への移植については、『Sun Studio 12: OpenMP API ユーザーズガイド』を参照してください。


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

2.8.15 MP taskloop

(SPARC) #pragma MP taskloop


注 –

Sun 固有の MP プラグマは推奨されず、サポートされません。代わりに、OpenMP 2.5 規格で規定された API をサポートします。標準命令への移植については、『OpenMP API ユーザーズガイド』を参照してください。


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

2.8.16 nomemorydepend

(SPARC) #pragma nomemorydepend

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

このプラグマのスコープは、プラグマから始まり、次のブロックの始まりか現在のブロック内のプラグマに続く最初の for ループ、または現在のブロックの終わりのいずれか先に達したところで終わります。プラグマは、スコープの終端に到達した時点で最初に見つかった for ループに適用されます。

2.8.17 no_side_effect

(SPARC) #pragma no_side_effect(<関数>[, <関数>…])

<関数> には、現行の翻訳単位内の関数名を指定します。 関数は、プラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。またプラグマはその関数の定義より前に指定されていなければいけません。指定した <関数> に対し、プラグマはその関数に一切の副作用がないことを宣言します。つまり、<関数> は渡された引数にだけ依存する結果の値を返します。<関数> および呼び出された子孫については、次のことがいえます。

コンパイラはこの情報を、その関数を用いる最適化に利用することができます。関数に副作用があると、この関数を呼び出すプログラムの実行結果は未定義になります。コンパイラはこの情報をレベル 3 以上の最適化に利用します。

2.8.18 opt

#pragma opt level (<関数>[, <関数>])

<関数> には、現行の翻訳単位内の関数名を指定します。 指定した関数に対する最適化レベルを指定します。0、1、2、3、4、5 のいずれかの最適化レベルを割り当てることができます。level を 0 に設定することによって、最適化を無効にできます。関 数は、プラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。プラグマは、最適化する関数の定義を処理する必要があります。

プラグマ内に指定される関数の最適化レベルは、-xmaxopt の値に下げられます。-xmaxopt=off の場合、プラグマは無視されます。

2.8.19 pack

#pragma pack(n)

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

このプラグマを使用すると、構造体または共用体のメンバーの境界整列を指定できます。たとえば、#pragma pack(2) を指定すると、int、long、long long、float、double、long double、pointer が、それぞれの自然境界ではなく、2 バイト境界に整列されます。

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

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

#pragma pack を使用する場合、構造体または共用体自身の整列条件は、その構造体または共用体でより厳密に境界整列されるメンバーの整列条件と同一です。したがって、その構造体または共有体の任意の宣言は pack の境界整列となります。たとえば、char 型だけの struct は整列の制限はありませんが、double 型を含む struct は 8 バイトの境界上に並びます。


注 –

#pragma pack を使用して構造体または共用体のメンバーを自然境界以外の境界で整列させると、通常、これらのフィールドへのアクセスが発生した場合に SPARC 上でバスエラーが起きます。このエラーを避けるには、-xmemalign オプションも指定します。このようなプログラムをコンパイルする最適な方法については、「B.2.111 -xmemalign=abを参照してください。


2.8.20 pipeloop

(SPARC) #pragma pipeloop(n )

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

このプラグマのスコープは、プラグマから始まり、次のブロックの始まりか現在のブロック内のプラグマに続く最初の for ループ、または現在のブロックの終わりのいずれか先に達したところで終わります。プラグマは、スコープの終端に到達した時点で最初に見つかった for ループに適用されます。

2.8.21 rarely_called

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

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

指定した関数は、このプラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。#pragma rarely_called の例を次に示します。


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

2.8.22 redefine_extname

#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_extname 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__ */

2.8.23 returns_new_memory

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

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

次の例に示すように、このプラグマは、指定した関数をプロトタイプまたは空のパラメータリストで宣言したあとでのみ使用できます。


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

2.8.24 unknown_control_flow

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

#pragma unknown_control_flow 指令は、呼び出し元のフローグラフを変更する手続きを説明するために使用されます。通常、この指令には setjmp() のような関数の宣言が伴います。Sun のシステム上では、インクルードファイル <setjmp.h> に次の指定が含まれています。


extern int setjmp();
#pragma unknown_control_flow(setjmp)

setjmp() のような特性を持つほかの関数も、同様に宣言する必要があります。

原則として、この属性を認識するオプティマイザは、制御フローグラフに適切な境界を挿入できます。これによって、setjmp() を呼び出す関数内で関数呼び出しを安全に処理しながら、影響を受けないフローグラフ部分のコードを最適化することが可能になります。

指定した関数は、このプラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。

2.8.25 unroll

(SPARC) #pragma unroll (unroll_factor )

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

このプラグマのスコープは、プラグマから始まり、次のブロックの始まりか現在のブロック内のプラグマに続く最初の for ループ、または現在のブロックの終わりのいずれか先に達したところで終わります。プラグマは、スコープの終端に到達した時点で最初に見つかった for ループに適用されます。

2.8.26 warn_missing_parameter_info

#pragma [no_]warn_missing_parameter_info

#pragma warn_missing_parameter_info を指定すると、パラメータ型情報が含まれない関数宣言を持つ関数の呼び出しに対して警告が発生します。次の例を考えてみましょう。


exmaple% cat -n t.c
     1    #pragma warn_missing_parameter_info
     2    
     3    int foo();
     4    
     5    int bar () {
     6    
     7       int i;
     8    
     9       i = foo(i);
    10    
    11       return i;
    12    }
% cc t.c -c -errtags
"t.c", line 9: 警告: function foo has no prototype (E_NO_MISSED_PARAMS_ALLOWED)
example%

#pragma no_warn_missing_parameter_info は、それ以前の #pragma warn_missing_parameter_info を無効にします。

デフォルトでは、#pragma no_warn_missing_parameter_infoは有効です。

2.8.27 weak

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

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


#pragma weak <シンボル>

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


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

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

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