この節では、C++ コンパイラにより認識されるプラグマキーワードについて説明します。
#pragma align integer(variable [,variable...])
align を使用すると、指定したすべての変数のメモリー境界を integer バイト境界に揃えることができます (デフォルト値より優先されます)。ただし、次の制限があります。
integer は、1 ~ 128 の範囲にある 2 の二乗、つまり、1、2、4、8、16、32、64、128 のいずれかでなければいけません。
variable には、大域変数か静的変数を指定します。局所変数またはクラスメンバー変数は指定できません。
指定された境界がデフォルトより小さい場合は、デフォルトが優先します。
この #pragma 行は、指定した変数の宣言より前になければいけません。前にないと、この #pragma 行は無視されます。
この #pragma 行で指定されていても、プラグマ行に続くコードの中で宣言されない変数は、すべて無視されます。次に、正しく宣言されている例を示します。
#pragma align 64 (aninteger, astring, astruct) int aninteger; static char astring[256]; struct S {int a; char *b;} astruct;
#pragma align を名前空間内で使用するときは、符号化された名前を使用する必要があります。たとえば、次のコード中の、#pragma align 文には何の効果もありません。この問題を解決するには、#pragma align 文の a、b、および c を符号化された名前に変更します。
namespace foo { #pragma align 8 (a, b, c) static char a; static char b; static char c; }
#pragma does_not_read_global_data(funcname [, funcname])
このプラグマは、指定したルーチンが直接的にも間接的にも大域データを読み込まないことをコンパイラに宣言します。この表明により、そうしたルーチンへの呼び出し前後のコードをさらに最適化することができます。具体的には、代入文やストア命令をそうした呼び出しの前後に移動することができます。
このプラグマを使用できるのは、指定した関数のプロトタイプを宣言したあとに限定されます。大域アクセスに関する表明が真でない場合は、プログラムの動作は未定義になります。
プラグマがその引数として多重定義関数を処理する方法の詳細は、「B.1.1 プラグマの引数としての多重定義関数」を参照してください。
#pragma does_not_return(funcname [, funcname])
指定した関数への呼び出しが復帰しないことをコンパイラに表明します。この表明により、コンパイラは、指定された関数への呼び出しが戻らないと仮定して最適化を行うことができます。たとえば、呼び出し側で終了したライフ回数を登録すると、より多くの最適化が可能となります。
指定した関数が復帰した場合は、プログラムの動作は未定義になります。
次の例のとおり、このプラグマを使用できるのは、指定した関数のプロトタイプを宣言したあとに限定されます。
extern void exit(int); #pragma does_not_return(exit) extern void __assert(int); #pragma does_not_return(__assert)
プラグマがその引数として多重定義関数を処理する方法の詳細は、「B.1.1 プラグマの引数としての多重定義関数」を参照してください。
#pragma does_not_write_global_data(funcname [, funcname])
このプラグマは、指定したルーチンが直接的にも間接的にも大域データを書き込まないことをコンパイラに宣言します。この表明により、そうしたルーチンへの呼び出し前後のコードをさらに最適化することができます。具体的には、代入文やストア命令をそうした呼び出しの前後に移動することができます。
このプラグマを使用できるのは、指定した関数のプロトタイプを宣言したあとに限定されます。大域アクセスに関する表明が真でない場合は、プログラムの動作は未定義になります。
プラグマがその引数として多重定義関数を処理する方法の詳細は、「B.1.1 プラグマの引数としての多重定義関数」を参照してください。
#pragma dumpmacros (value[,value...])
マクロがプログラム内でどのように動作しているかを調べたいときに、このプラグマを使用します。このプラグマは、定義済みマクロ、解除済みマクロ、実際の使用状況といった情報を提供します。マクロの処理順序に従って、標準エラー (stderr) に出力します。dumpmacros プラグマは、ファイルが終わるまで、または #pragma end_dumpmacro に到達するまで、有効です。「B.2.6 #pragma end_dumpmacros」 を参照してください。value の代わりに次の引数を使用できます。
|
注 - サブオプション loc、conds、sys は、オプション defs、undefs、use の修飾子です。loc、conds、sys は、単独では効果はありません。たとえば #pragma dumpmacros=loc,conds,sys には、何も効果はありません。
dumpmacros プラグマとコマンド行オプションの効果は同じですが、プラグマがコマンド行オプションを上書きします。「A.2.122 -xdumpmacros[= value[,value...]]」を参照してください。
dumpmacros プラグマは入れ子にならないので、次のコードでは #pragma end_dumpmacros が処理されるとマクロ情報の出力が停止します。
#pragma dumpmacros (defs, undefs) #pragma dumpmacros (defs, undefs) ... #pragma end_dumpmacros
dumpmacros プラグマの効果は累積的です。次のものは、
#pragma dumpmacros(defs, undefs) #pragma dumpmacros(loc)
次と同じ効果を持ちます。
#pragma dumpmacros(defs, undefs, loc)
オプション #pragma dumpmacros=use,no%loc を使用した場合、使用したマクロそれぞれの名前が一度だけ出力されます。オプション #pragma dumpmacros=use,loc を使用した場合、マクロを使用するたびに位置とマクロ名が出力されます。
#pragma end_dumpmacros
このプラグマは、dumpmacrospragma が終わったことを通知し、マクロ情報の出力を停止します。dumpmacros プラグマ終了時に end_dumpmacros プラグマを使用しなかった場合、dumpmacros プラグマはファイルが終わるまで出力を生成し続けます。
#pragma error_messages (on|off|default, tag… tag)
このエラーメッセージプラグマは、ソースプログラムの中から、コンパイラが発行するメッセージを制御可能にします。プラグマは警告メッセージにのみ効果があります。-w コマンド行オプションは、すべての警告メッセージを無効にすることでこのプラグマを上書きします。
#pragma error_messages (on, tag… tag)
on オプションは、先行する #pragma error_messages オプション (off オプションなど) をその時点で無効にして、-erroff オプションも無効にします。
#pragma error_messages (off, tag… tag)
off オプションは、コンパイラプログラムが指定トークンから始まる特定のメッセージを発行することを禁止します。この特定のエラーメッセージに対するプラグマの指定は、別の #pragma error_messages によって無効にされるか、コンパイルが終了するまで有効です。
#pragma error_messages (default, tag… tag)
default オプションは、指定タグについて、先行する #pragma error_messages 指令を無効にします。
#pragma fini (identifier[,identifier...])
fini を使用すると、identifier を「終了関数」にします。この関数は void 型で、引数を持ちません。この関数は、プログラム制御によってプログラムが終了する時、または関数内の共有オブジェクトがメモリーから削除されるときに呼び出されます。初期設定関数と同様に、終了関数はリンカーが処理した順序で実行されます。
ソースファイル内で #pragma fini で指定された関数は、そのファイルの中にある静的デストラクタのあとに実行されます。identifier は、この #pragma で指定する前に宣言しておく必要があります。
このような関数は #pragma fini 指令の中に登場するたびに、1 回呼び出されます。
hdrstop プラグマをソースファイルヘッダーに埋め込むと、活性文字列の終わりが指示されます。たとえば次のファイルがあるとします。
example% cat a.cc #include "a.h" #include "b.h" #include "c.h" #include <stdio.h> #include "d.h" . . . example% cat b.cc #include "a.h" #include "b.h" #include "c.h"
活性文字列は c.h で終わるので、各ファイルの c.h の後に #pragma hdrstop を挿入します。
#pragma hdrstop を挿入できる場所は、CC コマンドで指定したソースファイルの活性文字列の終わりだけです。#pragma hdrstop をインクルードファイル内に指定しないでください。
「A.2.162 -xpch=v」および 「A.2.163 -xpchstop=file」 を参照してください。
#pragma ident string
ident を使用すると、実行可能ファイルの .comment 部に、string に指定した文字列を記述できます。
#pragma init(identifier[,identifier...])
init を使用すると、identifier (識別子) を「初期設定関数」にします。この関数は void 型で、引数を持ちません。この関数は、実行開始時にプログラムのメモリーイメージを構築する時に呼び出されます。共有オブジェクトの初期設定子の場合、共有オブジェクトをメモリーに入れるとき、つまりプログラムの起動時または dlopen() のような動的ロード時のいずれかに実行されます。初期設定関数の呼び出し順序は、静的と動的のどちらの場合でもリンカーが処理した順序になります。
ソースファイル内で #pragma init で指定された関数は、そのファイルの中にある静的コンストラクタのあとに実行されます。identifier は、この #pragma で指定する前に宣言しておく必要があります。
このような関数は #pragma init 指令の中に登場するたびに、1 回呼び出されます。
#pragma must_have_frame(funcname [,funcname])
このプラグマは、(System V ABI で定義されているとおり) 完全なスタックフレームを必ず持つように、指定した関数リストをコンパイルすることを要求します。このプラグマで関数を列挙する前に、関数のプロトタイプを宣言する必要があります。
extern void foo(int); extern void bar(int); #pragma must_have_frame(foo, bar)
このプラグマを使用できるのは、指定した関数のプロトタイプの宣言後のみに限定されます。プラグマは関数の最後より先に記述する必要があります
void foo(int) { . #pragma must_have_frame(foo) . return; }
「B.1.1 プラグマの引数としての多重定義関数」を参照してください。
#pragma no_side_effect(name[,name...])
no_side_effect は、関数によって持続性を持つ状態が変更されないことを通知するためのものです。このプラグマは、指定された関数がどのような副作用も起こさないことをコンパイラに宣言します。すなわち、これらの関数は、渡された引数だけに依存する値を返します。さらに、これらの関数と、そこから呼び出される関数は、次の処理も行なってはいけません。
呼び出し時点で呼び出し側が認識できるプログラム状態の一部に、読み出しまたは書き込みのためにアクセスすることはありません。
入出力を実行しません。
呼び出し時点で認識できるプログラム状態のどの部分も変更しません。
コンパイラは、この情報を最適化に使用します。
関数に副作用があると、この関数を呼び出すプログラムの実行結果は未定義になります。
name 引数で、現在の翻訳単位に含まれている関数の名前を指定します。プラグマは関数と同じスコープ内になければならず、また、関数宣言後に位置していなければいけません。プラグマは、関数定義の前に位置していなければいけません。
プラグマがその引数として多重定義関数を処理する方法の詳細は、「B.1.1 プラグマの引数としての多重定義関数」を参照してください。
#pragma opt level (funcname[, funcname])
funcname には、現在の翻訳単位内で定義されている関数の名前を指定します。level の値は、指定した関数に対する最適化レベルです。0、1、2、3、4、5 いずれかの最適化レベルを割り当てることができます。level を 0 に設定すると、最適化を無効にできます。関数は、プラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。プラグマは、最適化する関数の定義を処理する必要があります。
プラグマ内に指定される関数の最適化レベルは、-xmaxopt の値に下げられます。-xmaxopt=off の場合、プラグマは無視されます。
プラグマがその引数として多重定義関数を処理する方法の詳細は、「B.1.1 プラグマの引数としての多重定義関数」を参照してください。
#pragma pack([n])
pack は、構造体メンバーの配置制御に使用します。
n を指定する場合は、0 または 2 の累乗にする必要があります。0 以外の値を指定すると、コンパイラは n バイトの境界整列と、データ型に対するプラットフォームの自然境界のどちらか小さい方を使用します。たとえば次の指令は、自然境界整列が 4 バイトまたは 8 バイト境界である場合でも、指令のあと (および後続の pack 指令の前) に定義されているすべての構造体のメンバーを 2 バイト境界を超えないように揃えます。
#pragma pack(2)
n が 0 であるか省略された場合、メンバー整列は自然境界整列の値に戻ります。
n の値がプラットフォームのもっとも厳密な境界整列と同じかそれ以上の場合には、自然境界整列になります。次の表に、各プラットフォームのもっとも厳密な境界整列を示します。
表 B-1 プラットフォームのもっとも厳密な境界整列
|
pack 指令は、次の pack 指令までに存在するすべての構造体定義に適用されます。別々の翻訳単位にある同じ構造体に対して異なる境界整列が指定されると、プログラムは予測できない状態で異常終了する場合があります。特に、コンパイル済みライブラリのインタフェースを定義するヘッダーをインクルードする場合は、その前に pack を使用しないでください。プログラムコード内では、pack 指令は境界整列を指定する構造体の直前に置き、#pragma pack() は構造体の直後に置くことをお勧めします。
SPARC プラットフォーム上で #pragma pack を使用して、型のデフォルトの境界整列よりも密に配置するには、アプリケーションのコンパイルとリンクの両方で -misalign オプションを指定する必要があります。次の表に、整数データ型のメモリーサイズとデフォルトの境界整列を示します。
表 B-2 メモリーサイズとデフォルトの境界整列 (単位はバイト数)
|
#pragms rarely_called(funcname[, funcname])
このプラグマは、指定の関数がほとんど呼び出されないことをコンパイラに示唆します。このヒントにより、コンパイラは、プロファイル収集段階に負担をかけることなく、ルーチンの呼び出し元でプロファイルフィードバック方式の最適化を行うことができます。このプラグマはヒントの提示ですので、コンパイラは、このプラグマに基づく最適化を行わないこともあります。
#pragma rarely_called プリプロセッサ指令を使用できるのは、指定の関数のプロトタイプが宣言されたあとだけです。次は、#pragma rarely_called の例です。
extern void error (char *message); #pragma rarely_called(error)
プラグマがその引数として多重定義関数を処理する方法の詳細は、「B.1.1 プラグマの引数としての多重定義関数」を参照してください。
#pragma returns_new_memory(name[,name...])
このプラグマは、指定した関数が新しく割り当てられたメモリーのアドレスを返し、そのポインタがほかのポインタの別名として使用されないことをコンパイラに宣言します。この情報により、オプティマイザはポインタ値をより正確に追跡し、メモリー位置を明確化することができます。この結果、スケジューリングとパイプライン化が改善されます。
このプラグマの宣言が実際には誤っている場合は、該当する関数を呼び出したプログラムの実行結果は保証されません。
name 引数で、現在の翻訳単位に含まれている関数の名前を指定します。プラグマは関数と同じスコープ内になければならず、また、関数宣言後に位置していなければいけません。プラグマは、関数定義の前に位置していなければいけません。
プラグマがその引数として多重定義関数を処理する方法の詳細は、「B.1.1 プラグマの引数としての多重定義関数」を参照してください。
#pragma unknown_control_flow(name[,name...])
unknown_control_flow を使用すると、手続き呼び出しの通常の制御フロー属性に違反するルーチンの名前のリストを指定できます。たとえば、setjmp() の直後の文は、ほかのどんなルーチンを呼び出してもそこから返ってくることができます。これは、longjmp() を呼び出すことによって行います。
このようなルーチンを使用すると標準のフローグラフ解析ができないため、呼び出す側のルーチンを最適化すると安全性が確保できません。このような場合に #pragma unknown_control_flow を使用すると安全な最適化が行えます。
関数名が多重定義されている場合、最後に宣言された関数が選ばれます。
#pragma weak name1 [= name2]
weak を使用すると、弱い (weak) 大域シンボルを定義できます。このプラグマは主にソースファイルの中でライブラリを構築するために使用されます。リンカーは弱いシンボルを認識できなくてもエラーメッセージを出しません。
weak プラグマは、次の 2 つの書式でシンボルを指定できます。
文字列書式。文字列は、C++ の変数または関数の符号化された名前でなければいけません。無効な符号化名が指定された場合、その名前を参照したときの動作は予測できません。無効な符号化名を参照した場合、バックエンドがエラーを生成するかどうかは不明です。エラーを生成するかどうかに関わらず、無効な符号化名を参照したときのバックエンドの動作は予測できません。
識別子書式。識別子は、コンパイル単位内であらかじめ宣言された C++ の関数のあいまいでない識別子でなければいけません。識別子書式は変数には使用できません。無効な識別子への参照を検出した場合、フロントエンド (ccfe) はエラーメッセージを生成します。
#pragma weak name という書式の指令は、name を弱い (weak) シンボルに定義します。name のシンボル定義が見つからなくても、リンカーはエラーメッセージを生成しません。また、弱いシンボルの定義を複数見つけた場合でも、リンカーはエラーメッセージを生成しません。リンカーは単に最初に検出した定義を使用します。
プラグマ name の強い定義が存在しない場合、リンカーはシンボルの値を 0 にします。
次の指令は、ping を弱いシンボルに定義しています。ping という名前のシンボルの定義が見つからない場合でも、リンカーはエラーメッセージを生成しません。
#pragma weak ping
#pragma weak name1 = name2 という書式の指令は、シンボル name1 を name2 への弱い参照として定義します。name1 がどこにも定義されていない場合、name1 の値は name2 の値になります。name1 が別の場所で定義されている場合、リンカーはその定義を使用し、name2 への弱い参照は無視します。次の指令では、bar がプログラムのどこかで定義されている場合、リンカーはすべての参照先を bar に設定します。そうでない場合、リンカーは bar への参照を foo にリンクします。
#pragma weak bar = foo
識別子書式では、name2 は現在のコンパイル単位内で宣言および定義しなければいけません。次に例を示します。
extern void bar(int) {...} extern void _bar(int); #pragma weak _bar=bar
文字列書式を使用する場合、シンボルはあらかじめ宣言されている必要はありません。次の例において、_bar と bar の両方が extern "C" である場合、その関数はあらかじめ宣言されている必要はありません。しかし、bar は同じオブジェクト内で定義されている必要があります。
extern "C" void bar(int) {...} #pragma weak "_bar" = "bar"
識別子書式を使用するとき、プラグマのあるスコープ中には指定した名前を持つ関数は、1 つしか存在してはいけません。多重定義関数に識別子書式の #pragma weak を使おうとすると、エラーになります。次に例を示します。
int bar(int); float bar(float); #pragma weak bar // error, ambiguous function name
このエラーを回避するには、文字列書式を使用します。例を次に示します。
int bar(int); float bar(float); #pragma weak "__1cDbar6Fi_i_" // make float bar(int) weak
詳細は、Solaris の『リンカーとライブラリ』を参照してください。