#pragma
指示文は,コンパイラごとに異なる機能をインプリメントするための標準的な方法です。
この章では,C コンパイラでサポートされている処理系固有のプラグマについて説明します。
#pragma assert
(3.1 節)
#pragma environment
(3.2 節)
#pragma extern_model
(3.3 節)
#pragma extern_prefix
(3.4 節)
#pragma inline
(3.5 節)
#pragma intrinsic
および
#pragma function
(3.6 節)
#pragma linkage
(3.7 節)
#pragma member_alignment
(3.8 節)
#pragma message
(3.9 節)
#pragma optimize
(3.10 節)
#pragma pack
(3.11 節)
#pragma pointer_size
(3.12 節)
#pragma unroll
(3.13 節)
#pragma use_linkage
(3.14 節)
#pragma weak
(3.15 節)
Compaq C のすべてのインプリメンテーションでサポートされているプラグマについては,『Compaq C 言語リファレンス・マニュアル』に記載があります。
プラグマの中には,デフォルトでマクロ展開を実行するものがあります。 『Compaq C 言語リファレンス・マニュアル』にそのようなプラグマの一覧があります。 プラグマ名やキーワードと同じ名前のマクロを定義しているプログラムを移植する際に,マクロ展開を避けるため,接頭語としてプラグマ名に下線を 2 つ付ける方法についても説明しています。
プラグマ名に接尾語の
_m
を付加すると,どのプラグマに対してもマクロ展開を強制することができます。
プラグマ名の後に
_m
がある場合,プラグマ名の後のテキストはマクロ置換であると見なされます。
3.1.3 項
の例を参照してください。
3.1 #pragma assert 指示文
#pragma assert
指示文を使用すると,コンパイラがより効率的なコードを生成するために使用できる,プログラムに関するアサーションを指定できます。
#pragma assert
指示文は,プログラムを正しく動作させるために必要なものではありません。
ただし,#pragma assert
を指定する場合は,指定するアサーションが正しくないと,プログラムが誤動作するおそれがあります。
#pragma assert
指示文の形式は次のとおりです。
#pragma assert func_attrs(identifier-list)function-assertions
#pragma assert global_status_variable(variable-list)
#pragma assert non_zero(constant-expression) "string-literal"
3.1.1 #pragma assert func_attrs
この形式の
#pragma assert
指示文を使用すると,関数の属性にアサーションが設定されます。
この形式のプラグマの構文は,次のとおりです。
#pragma assert func_attrs(identifier-list)function-assertions
関数識別子のリスト。 コンパイラは,function-assertions に基づいて,これらの関数に仮定条件を設定できます。 複数の識別子を指定する場合は,コンマで区切ります。
関数に対してコンパイラが仮定条件を設定するために使用するアサーションのリスト。 以下のアサーションの中から 1 つ以上指定し,複数指定する場合はホワイト・スペースで区切ります。
noreturn
コンパイラは,ルーチンを呼び出した後,ルーチンから戻らないものと仮定することができます。
nocalls_back
コンパイラは,この関数から制御を戻すまでは,そのソース・モジュール内のルーチンが呼び出されないと仮定することができます。
nostate
コンパイラは,関数のリターン値が関数の引数のみによって決まり,この関数には副作用がないと仮定することができます。 関数に対して noeffects と nostate の両方がマークされると,コンパイラは,この関数への重複する呼び出しを削除することができます。
noeffects
コンパイラは,この関数には,関数のリターン値の設定以外の効果がないと仮定することができます。 コンパイラは,関数呼び出しからのリターン値が一度も使用されないと判断した場合,その呼び出しを削除することができます。
file_scope_vars(
option)
コンパイラは,ファイル範囲で (内部または外部リンケージで) 宣言された変数に関数がアクセスする方法についての仮定条件を設定できます。 option は,以下のキーワードのいずれかになります。
none
関数は,型が
volatile
でなく,また
#pragma assert global_status_variable
にリストされていないファイル範囲の変数に対して,読み取りも書き込みも行いません。
noreads
関数は,型が
volatile
でなく,また
#pragma assert global_status_variable
にリストされていないファイル範囲の変数に対して,読み取りを行いません。
nowrites
関数は,型が
volatile
でなく,また
#pragma assert global_status_variable
にリストされていないファイル範囲の変数に対して,書き込みを行いません。
format (
style,
format-index,
first-to-check-index)
コンパイラは,フォーマット文字列に対して型検査される
printf
または
scanf
スタイルの引数をこの関数が取ると仮定することができます。
フォーマット属性により,引数としてフォーマット文字列を取る独自の関数を指定して,コンパイラにこれらの関数への呼び出しのエラーをチェックさせることができます。
コンパイラは,ライブラリ関数
printf
,fprintf
,sprintf
,snprintf
,scanf
,fscanf
,sscanf
に対して,intrinsic が有効になっている場合 (省略時) に,フォーマットをチェックします。
フォーマット属性を使用すると,これらの関数に対して intrinsic が有効でない場合に,フォーマットがチェックされるようにすることができます。
フォーマット文字列の解釈方法を指定します。printf
と
scanf
のいずれかを指定します。
どの引数がフォーマット文字列引数かを指定します (1 から始まる)。
フォーマット文字列に対してチェックを行う,最初の引数の番号を指定します。
チェックする引数がない場合 (vprintf
など) は,3 番目のパラメータにゼロを指定します。
この場合,コンパイラはフォーマット文字列に矛盾がないことだけをチェックします。
たとえば,次のように宣言すると,コンパイラは
your_printf
の呼び出しの引数について,printf
スタイルのフォーマット文字列引数
your_format
との整合性をチェックします。
extern int your_printf (void *your_object, const char *your_format, ...); #pragma assert func_attrs(your_printf) format (printf, 2, 3)
フォーマット文字列 (your_format
) は,関数
your_printf
の 2 番目の引数であり,チェックする引数は 3 番目の引数から始まるので,フォーマット属性の正しいパラメータは,2 と 3 です。
この形式の
#pragma assert
指示文は,ファイル範囲に記述しなければなりません。
identifier-list
内の識別子は,#pragma assert
指示文の位置から見えるところで宣言されていなければなりません。
各
#pragma assert func_attrs
指示文で異なるアサーションを指定する限りは,複数の指示文に同じ関数を記述できます。
たとえば,次の記述は有効です。
#pragma assert func_attrs(a) nocalls_back #pragma assert func_attrs(a) file_scope_vars(noreads)
次の記述は無効です。
#pragma assert func_attrs(a) file_scope_vars(noreads) #pragma assert func_attrs(a) file_scope_vars(nowrites)
3.1.2 #pragma assert global_status_variable
この形式の
#pragma assert
指示文を使用すると,グローバル状態変数とみなされる変数を指定できます。
グローバル状態変数は,#pragma assert func_attrs file_scope_vars
指示文によって関数に指定されるアサーションから除外されます。
この形式の指示文の構文は次のとおりです。
#pragma assert global_status_variable(variable-list)
variable-list は変数のリストです。
この形式の
#pragma assert
指示文は,ファイル範囲に記述しなければなりません。
variable-list
内の変数は,#pragma assert
指示文の位置から見えるところで宣言されていなければなりません。
3.1.3 #pragma assert non_zero
この形式の
#pragma assert
指示文の構文は次のとおりです。
#pragma assert non_zero(constant-expression) "string-literal"
コンパイラは,この指示文を見つけると constant-expression を評価します。 式がゼロであれば,コンパイラは,指定した文字列リテラルとコンパイル時定数の両方を含むメッセージを出力します。 たとえば,次のように指定したとします。
#pragma assert non_zero(sizeof(a) == 12) "a is the wrong size"
コンパイラは,sizeof(a) が 12 でないと判断した場合に次のようなメッセージを出力します。
cc: Warning: a.c, line 4: The assertion "sizeof(a)==12" was not true, a is the wrong size. (assertfail)
assert
オプションの
func_attrs
および
global_status_variable
の場合と異なり,#pragma assert non_zero
は関数本体の内部と外部のどちらにも置くことができます。
関数本体の内部で使用する場合,#pragma
は文を記述できる位置に記述できますが,文として扱われることはありません。
関数本体の外部で使用する場合,#pragma
は宣言を記述できる位置に記述できますが,宣言として扱われることはありません。
constant-expression
内の変数は,#pragma assert
指示文の位置から見えるところで宣言されていなければなりません。
#pragma assert
はプラグマに対してマクロ置換を行わないので,#pragma assert_m
指示文を使用しなければならない場合があります。
次に示すような,struct
のサイズと,そのいずれかの要素のオフセットの両方を確認するプログラムがあるとします。
#include <stddef.h> typedef struct { int a; int b; } s; #pragma assert non_zero(sizeof(s) == 8) "sizeof assert failed" #pragma assert_m non_zero(offsetof(s,b) == 4) "offsetof assert failed"
offsetof
はマクロなので,2 番目の指示文を
assert_m
にして,offsetof
が正しく展開されるようにしなければなりません。
3.2 #pragma environment 指示文
#pragma environment
指示文を使用すると,すべてのコンテキスト・プラグマの状態を設定,保存,リストアすることができます。
コンテキスト・プラグマには,次のものがあります。
#pragma extern_model
#pragma extern_prefix
#pragma member_alignment
#pragma message
#pragma pack
#pragma pointer_size
コンテキスト・プラグマは以前の状態の保存とリストアを行うプラグマであり,通常は,同じタイプのプラグマを使用するヘッダ・ファイルを取り込む前後の状態です。
#pragma environment
指示文は,インクルード・ファイルを周囲のプログラムで設定されるコンパイル・コンテキストから保護するとともに,周囲のプログラムを,それがインクルードするヘッダ・ファイルで設定されるコンテキストから保護します。
このプラグマの構文は次のとおりです。
#pragma
environment [ command_line | header_defaults | restore | save
]
command_line
すべてのコンテキスト・プラグマの状態を,コマンド行に指定されたとおりに設定します。 このプラグマを使用すると,ヘッダ・ファイルが取り込まれる前に有効になる環境プラグマからヘッダ・ファイルを保護します。
header_defaults
すべてのコンテキスト・プラグマの状態を省略時の値に設定します。
これは,コマンド行オプションもプラグマも指定しないでプログラムをコンパイルした状況と同等ですが,このプラグマはヘッダ・ファイルに適するようにプラグマ・メッセージ状態を
#pragma nostandard
に設定します。
restore
すべてのコンテキスト・プラグマの現在の状態をリストアします。
save
すべてのコンテキスト・プラグマの現在の状態を保存します。
ソース・コードを変更しなくても,#pragma environment
を使用することにより,追加のコンパイル・コンテキストをもたらす可能性のある言語の拡張などからヘッダ・ファイルを保護することができます。
ヘッダ・ファイルは取り込んだファイルからプラグマの状態を選択して継承することができ,その後,追加のプラグマを必要に応じて使用することにより,コンパイルを非省略時の状態に設定します。 次の例を参照してください。
#ifdef _ _pragma_environment #pragma _ _environment save [1] #pragma _ _environment header_defaults [2] #pragma member_alignment restore [3] #pragma member_alignment save [4] #endif . . /*contents of header file*/ . #ifdef _ _pragma_environment #pragma _ _environment restore #endif
この例に関する説明は次のとおりです。
すべてのコンテキスト・プラグマの状態を保存します。 [例に戻る]
省略時のコンパイル環境を設定します。 [例に戻る]
#pragma _ _environment save
によってプッシュされた
#pragma member_alignment
スタックから,メンバ位置合わせコンテキストをポップして,メンバ位置合わせコンテキストを以前の状態にリストアします。
[例に戻る]
メンバ位置合わせコンテキストをスタックにプッシュして戻し,#pragma _ _environment restore
がエントリをポップできるようにします。
[例に戻る]
このように,ヘッダ・ファイルが継承するメンバ位置合わせコンテキストを除き,ヘッダ・ファイルはすべてのプラグマから保護されています。
3.3 #pragma extern_model 指示文
#pragma extern_model
指示文は,外部リンケージを持つデータ・オブジェクトをコンパイラがどう解釈するかを制御します。
このプラグマを使用すると,外部 (extern
) オブジェクトに使用するグローバル・シンボル・モデルを次のモデルの中から選択できます。
relaxed_refdef
このモデルでは,宣言には参照と定義があります。 同じオブジェクトに対して初期化されていない定義が複数あっても構いません。 リンカが解決して 1 つにまとめます。 ただし,参照するためには少なくとも 1 つの定義がなければなりません。 このモデルはほとんどの UNIX システムの C コンパイラで使用され,Compaq C の省略時モデルもこのモデルになっています。
strict_refdef
このモデルでは,宣言には参照と定義があります。 参照されるどのシンボルに対しても,プログラム内での定義は正確に 1 つだけでなければなりません。 このモデルは,ANSI C への厳密な準拠が保証される唯一のモデルです。
注意
HP OpenVMS プラットフォームの Compaq C では,これ以外に,
common_block
およびglobalvalue
という名前の 2 つのモデルをサポートしていますが,これらは Tru64 UNIX ではサポートしていません。
extern_model
プラグマでグローバル・シンボル・モデルを選択すると,別の
extern_model
プラグマを指定するまで,外部記憶クラスを持つオブジェクトの宣言は,すべて指定したモデルに従って処理されます。
たとえば,次のようなプラグマがあるとします。
#pragma extern_model strict_refdef "progsec3"
このプラグマを指定すると,それ以降のファイルレベルの宣言は,strict_refdef
モデルに従ったグローバル・シンボルの宣言として処理されます。
int x = 0; extern int y;
外部モデルが何であっても,コンパイラは ANSI C の規則に従って宣言が定義と参照のどちらかを判断します。
外部定義は,記憶クラス・キーワードがないファイルレベルの宣言か,または記憶クラス・キーワード
extern
を含むファイルレベルの宣言で,初期化されているものです。
外部参照は,記憶クラス・キーワード
extern
のある宣言で,初期化されていないものです。
上記の例では,x
の宣言はグローバル定義であり,y
の宣言はグローバル参照です。
ヘッダ・ファイルとプログラム・テキストの小さい範囲で,他の部分への影響なしに
#pragma extern_model
を使用できるように,コンパイラの外部モデル状態のスタックが用意されています。
詳細は,3.3.4 項
および
3.3.5 項
を参照してください。
以下の項では,#pragma extern_model
指示文のさまざまな形式について説明します。
3.3.1 構文
#pragma extern_model
指示文の構文は次のとおりです。
#pragma extern_model
model_spec
[attr[,attr]...]
次のいずれかです。
relaxed_refdef
strict_refdef "name"
"name"
は,任意の定義に対するプログラム・セクション (psect) の名前です。
[attr[,attr]...]
psect 属性の指定 (省略可能)。 以下に示す属性指定セットの中から 1 つだけ選択します。
shr
|noshr
psect は,メモリ内で共有できる (shr
) 場合と共有できない (noshr
) 場合があります。
省略時は
noshr
です。
wrt
|nowrt
psect に含まれるデータは,変更できる (wrt
) 場合と変更できない (nowrt
) 場合があります。
省略したときは,psect 内の最初の変数によって決まります。
変数に
const
型修飾子 (または
readonly
識別子) がある場合,psect は
nowrt
に設定されます。
それ以外の場合は,wrt
に設定されます。
ovr
|con
同じ名前の psect は,連結されるか (con
),または同じメモリ位置にオーバレイされます (ovr
)。
省略時は,strict_refdef
では
con
,relaxed_refdef
では
over
になります。
4
|octa
|5
|6
|7
|8
|9
|10
|11
|12
|13
|14
|15
|16
|page
これは,数値データの整列方法を指定します。
省略時の整列は
octa
です。
数値を指定すると,psect は,2 のその数値乗の位置に整列されます。
strict_refdef
extern_model では,次のような psect 属性を指定することもできます。
noreorder
この属性を指定すると,セクション内の変数が,定義した順に割り付けられます。 この属性指定は,省略時はオフになっています。
次の例では,初期化された変数が 64 KB (2**16) の境界に整列されます。
noreorder
属性指定は,変数が宣言された順に割り付けられることを意味します。
#pragma extern_model save #pragma extern_model strict_refdef "progsecA" 16,noreorder int var1 = 5; int var2 = 6; #pragma extern_model restore
次の例では,(書き込み不可の) 変数が,データ・キャッシュ・ラインの境界に整列されます。
#pragma extern_model save #pragma extern_model strict_refdef "progsecB" 3,noreorder,nowrt const long c_v1 = 1; const long c_v2 = 2; const long c_v3 = 2; const long c_v4 = 2; #pragma extern_model restore
relaxed_refdef
モデルでは,psect 属性は,仮定義で宣言した変数に影響を与えません。
次のようなコードがあったとします。
#pragma extern_model relaxed_refdef 5 int a; int b=6; #pragma extern_model strict_refdef 5 int c;
変数
a
は仮定義なので,省略時の octa ワード (2**4 つまり 16 バイト) の境界に整列されます。
しかし,b
は初期化されているので 32 バイト (2**5) の境界に整列されます。
c
は仮定義ですが,strict_refdef
モデルで定義されているので 32 バイト (2**5) の境界に整列されます。
注意
通常,psect 属性はシステム・プログラマが使用します。 システム・プログラマは,通常はマクロ内で行われる宣言をしなければなりません。 これらの属性のほとんどは,通常の C プログラムでは不要です。
3.3.2 #pragma extern_model relaxed_refdef
このプラグマは,コンパイラの外部データのモデルを,UNIX システムで使用される
relaxed_refdef
モデルとします。
#pragma extern_model relaxed_refdef
指示文の構文は,次のとおりです。
#pragma extern_model relaxed_refdef [attr[,attr]...]
3.3.3 #pragma extern_model strict_refdef
このプラグマは,コンパイラの外部データのモデルを
strict_refdef
モデルとします。
このモデルは,プログラムを ANSI C に厳密に準拠させたいときに使用します。
#pragma extern_model strict_refdef
指示文の構文は,次のとおりです。
#pragma extern_model strict_refdef "name" [attr[,attr]...]
引用符に囲まれた
name
を指定すると,定義に対する psect の名前になります。
3.3.4 #pragma extern_model save
このプラグマは,コンパイラの現在の外部モデルをスタックにプッシュします。
スタックには,shr/noshr
状態や引用符で囲まれた psect 名など,外部モデルに対応する情報がすべて記録されます。
このプラグマの構文は次のとおりです。
#pragma extern_model save
#pragma extern_model
スタックに保存できるエントリの数は,コンパイラが使用できるメモリ容量のみによって制限されます。
3.3.5 #pragma extern_model restore
このプラグマは,コンパイラの外部モデルのスタックをポップします。
スタックからポップされた内容で外部モデルの状態が設定されます。
スタックには,shr/noshr
状態や引用符で囲まれた psect 名など,外部モデルに対応する情報がすべて記録されます。
このプラグマの構文は次のとおりです。
#pragma extern_model restore
空のスタックをポップすると,警告メッセージが出力され,コンパイラの外部モデルは変わりません。
3.4 #pragma extern_prefix 指示文
#pragma extern_prefix
指示文は,コンパイラの外部名合成を制御します。
リンカはこの外部名を使って,外部名要求を解決します。
文字列引数を使って
#pragma extern_prefix
を指定すると,C コンパイラは,プラグマ指定に続く宣言によって生成されたすべての外部名の冒頭にその文字列を付加します。
このプラグマは,ライブラリを作成する上で有用です。 このライブラリを利用して,機能コードをライブラリ内の外部名に付加できます。
このプラグマの構文は,次のとおりです。
#pragma extern_prefix "string" [(id,...)]
#pragma extern_prefix save
#pragma extern_prefix restore
引用符で囲まれた string は,プラグマ指定に続く宣言内の外部名に付加されます。
オプション・リスト [(id,...)] を使って,特定の外部識別子に接頭語を指定することもできます。
save
および
restore
キーワードは,それぞれ現在のプラグマ接頭語文字列の保存,および保存済みのプラグマ接頭語文字列のリストアに使用できます。
プラグマによって指定されなかった場合,省略時の外部識別子用の接頭語は空文字列です。
推奨される使用法は,次のとおりです。
#pragma extern_prefix save #pragma extern_prefix " prefix-to-prepend-to-external-names " ...some declarations and definitions ... #pragma extern_prefix restore
extern_prefix
が有効であり,#include
を使ってヘッダ・ファイルをインクルードしているときに,extern_prefix
をヘッダ・ファイルの
extern
宣言に適用したくない場合は,次の順序でコードを記述します。
#pragma extern_prefix save #pragma extern_prefix "" #include ... #pragma extern_prefix restore
上記の順序で指定しない場合,インクルードされたファイル内での定義について,接頭語が外部識別子の冒頭に付加されます。
注意
#pragma extern_prefix
でオプションの識別子を指定する際に,以下の内容が適用されます。
各 id について,プラグマの位置にその id の可視状態の宣言が存在してはなりません。 存在していると,警告が発行されて,その id に対する効果はありません。
空でない接頭語を持つプラグマによる影響を受けた各 id は,同じコンパイル単位内で外部リンケージを使った宣言が行われることが期待されます。 コンパイルの終了までにそのような宣言が存在しない場合,コンパイラは省略時の情報を発行します。
id リスト形式のプラグマ,またはリストされた id の宣言を,他の形式のプラグマが制御するソース・コード領域内に配置することは許容されています。 2 つの形式が相互に作用し合うことはありません。 id リスト形式は,常に他の形式に優先します。
save
/restore
スタックと id リストとが,相互に作用することはありません。複数のプラグマに同一の id が使用される場合,2 番目のプラグマの接頭語が空
(""
) であるか,または前のプラグマの接頭語と一致する場合を除き,省略時のメッセージが発行されます。 どんな場合であっても,最後に遭遇した接頭語が他のすべてに優先されます。
関数のインライン化とは,関数呼び出しのインライン展開を意味します。 つまり,関数呼び出しを関数コードそのものと置換します。 関数のインライン展開は,関数呼び出しのオーバヘッドを無くすとともに,展開したコードにコンパイラの一般的な最適化手法を適用することによって,実行時間を短縮します。 マクロの使用と比較すると関数のインライン化には次のような利点があります。
引数の評価は 1 回だけでよい。
優先順序の問題を避けるためのカッコの濫用が不要である。
実際の展開はコマンド行で制御できる。
インライン展開をしない場合と意味規則は全く同じである。 マクロを使用した場合は,全く同じではない。
次のプリプロセッサ指示文が,関数のインライン化を制御します。
#pragma inline (id, ...)
#pragma noinline (id, ...)
このとき,id は関数 ID です。
#pragma inline
指示文で関数が指定されている場合,その関数の呼び出しは,可能であれば,インライン・コードとして展開されます。
#pragma noinline
指示文で関数が指定されている場合は,その関数はインライン・コードとして展開されません。
同じ関数が
#pragma inline
指示文および
#pragma noinline
指示文の両方で指定されている場合は,エラー・メッセージが発行されます。
関数をインライン展開する場合は,その関数定義を関数呼び出しと同じモジュールに記述しておく必要があります (-ifo オプションを指定してモジュール間でのインライン展開を可能にしている場合を除く)。 この定義の位置は,関数呼び出しの前でも後でも構いません。
cc
コマンドにオプション
-O3
,-O4
,-inline size
,-inline speed
,あるいは
-inline all
が指定されている場合,コンパイラは,#pragma inline
あるいは
#pragma noinline
指示文のどちらにも指定されていない関数の呼び出しのうち適切なものに関して展開します。
この場合,展開するかどうかは次の関数特性によって決定されます。
大きさ
その関数の呼び出し回数
次の制限を満たしている関数
パラメータのアドレスを扱わない。
struct
引数のフィールド。
struct
へのポインタである引数は制限されない。
関数の引数にアクセスするために
varargs
あるいは
stdarg
パッケージを使用していない。
これらのパッケージは引数が補助メモリ位置にあることを要求しますが,インライン展開はこれを満たしません。
最適化レベル
-O2
では,C コンパイラは小さな静的ルーチンだけをインライン化します。
#pragma inline
指示文は,大きさや呼び出し回数にかかわらずインライン展開するようにします。
3.6 #pragma intrinsic および #pragma function 指示文
intrinsic
として宣言できる関数もあります。
Intrinsics 関数の中では,ある状況で関数呼び出しを避けるために,C コンパイラが最適化コードを生成します。
表 3-1
に Intrinsics として宣言できる関数を示します。
表 3-1: Intrinsics 関数
abs |
fabs |
labs |
printf |
fprintf |
sprintf |
strcpy |
strlen |
memcpy |
memmove |
memset |
alloca |
bcopy |
bzero |
関数が Intrinsics として扱われるかどうかを制御するには,次の指示文のうちのいずれかを使用します。 func_name_list は,コンマで区切った複数の関数名をカッコで囲んだリストです。
#pragma intrinsic (func_name_list)
#pragma function (func_name_list)
#pragma function ()
#pragma intrinsic
指示文は,関数の Intrinsics としての処理を使用可能にします。
#pragma intrinsic
指示文が有効に設定されると,コンパイラは関数がどのように動作するかを認識するため,より効率的なコードを生成します。
関数の宣言は,プラグマが処理されるときに有効でなければなりません。
#pragma function
指示文は,関数の Intrinsics としての処理を使用不能にします。
空の
func_name_list
を持つ関数プラグマは,すべての関数に対する Intrinsics としての処理を使用不能にします。
コンパイラに対応する組み込み (built-in) を持つ標準ライブラリ関数もあります。 組み込みは関数の同義名で,関数を Intrinsics として宣言する処理に似ています。 次の表のような組み込みが提供されています。
関数 | 同義名 |
abs |
_ _builtin_abs |
labs |
_ _builtin_labs |
fabs |
_ _builtin_fabs |
alloca |
_ _builtin_alloca |
strcpy |
_ _builtin_strcpy |
Intrinsics や組み込み関数は,いくつかの手法で使用することができます。
関数の宣言を持つヘッダ・ファイルは,表 3-1
に示す関数用の
#pragma intrinsic
指示文を持っています。
このプラグマを使用可能にするには,プリプロセッサ・マクロ
_INTRINSICS
を定義しなければなりません。
alloca
に対しては,alloca.h
をインクルードするだけです。
たとえば,abs
の Intrinsics 関数を得るためには,プログラムは
stdlib.h
をインクルードして,-D_INTRINSICS
でコンパイルするか,または
stdlib.h
をインクルードする前に,_INTRINSICS
を
#define
指示文で定義する必要があります。
組み込み処理を使用可能にする方法の 1 つに,-D
スイッチを使用する方法があります。
たとえば,fabs
の組み込みを使用可能にするには,次のいずれかの方法でコンパイルします。
%
cc -Dfabs=_ _builtin_fabs prog.c
%
cc -Dabs=_ _builtin_abs prog.c
ここまでの関数の Intrinsics としての処理は,関数とその使用方法によって異なります。 最適化の結果は次のとおりです。
次の関数はインライン化される。
abs
fabs
labs
alloca
関数呼び出しのオーバヘッドが低減します。
場合によっては,printf
および
fprintf
関数は変換され,形式文字列と引数の数および種類によって,puts
,putc
,fputs
,fputc
,あるいはこれらと同等の関数を呼び出す。
特定のインスタンスでは,sprintf
関数は,strcpy
の呼び出しにインライン化あるいは変換される。
strcpy
関数は,ソース文字列 (2 番目の引数) が文字列リテラルの場合にはインライン化される。
#pragma linkage
指示文を使用すると,リンケージ・タイプを指定することができます。
リンケージ・タイプは,関数によるレジスタの使用方法を指定します。
これを使用すると,関数が使用するレジスタを指定することができます。
また,関数の特性 (たとえば,パラメータを引き渡したり,値を返すレジスタ) や,関数が変更できるレジスタも指定することができるようになります。
#pragma use_linkage
指示文は,以前に定義されたリンケージを関数と対応付けます (3.14 節を参照)。
#pragma linkage
指示文は,(関数が C で書かれている場合) 呼び出し側と関数コンパイルの両方に作用します。
関数がアセンブラで書かれている場合は,リンケージ・プラグマを使用して,アセンブラがレジスタを使用する方法を記述することができます。
#pragma linkage
指示文の構文は,次のとおりです。
#pragma linkage
linkage-name
= (characteristics)
定義するリンケージ・タイプを識別します。 C 識別子の形式で指定します。 リンケージ・タイプは固有の名前空間を持っているため,コンパイル単位内の他の識別子やキーワードと競合することはありません。
パラメータが引き渡される場所,関数の結果が返される場所,および関数呼び出しによって変更されるレジスタに関する情報を指定します。
register-list
を指定する必要があります。
register-list
は,rn
または
fn
のいずれかのレジスタ名をコンマで区切ったリストです。
register-list
にはカッコで囲んだサブリストを含めることができます。
register-list
を使用して,構造体の引数や関数の結果型を記述します。
このとき,構造体の各メンバは単一のレジスタで引き渡されます。
たとえば,次のように指定します。
parameters(r0,(f0,f1))
これは 2 つのパラメータを持つ関数の例です。
最初のパラメータはレジスタ
r0
に引き渡されます。
2 番目のパラメータは 2 つの浮動小数点メンバを持つ構造体型であり,レジスタ
f0
と
f1
に渡されます。
次の characteristics のリストは,項目をコンマで区切ってカッコで囲んで指定することができます。 これらのキーワードは任意の順に指定できます。
parameters (register-list
)
parameters
特性は,引数を特定のレジスタでルーチンへ引き渡します。
register-list の各項目には,ルーチンに引き渡す 1 つのパラメータを記述します。
構造体の引数は値によって引き渡すことができますが,構造体の各メンバは別々のパラメータ位置に引き渡されるという制約があります。 ただし,このようにすると,多数のレジスタが使用されるため,作成されるコードの処理速度が遅くなります。 コンパイラは,この状態を診断しません。
parameters
オプションで有効なレジスタは,r0
から
r25
までの整数レジスタと,f0
から
f30
までの浮動小数点レジスタです。
構造体型は,各フィールドに対し最低 1 つのレジスタを必要とします。 構造体型で必要なレジスタ数が,プラグマで提供される数と同じであることがコンパイラによって確認されます。
result (register-list)
コンパイラは,関数が値を返すためにどのレジスタを使用するかを認識しておく必要があります。
この情報は
result
特性を使用して引き渡します。
関数が値を返さない (つまり,関数のリターン型が
void
) 場合は,リンケージの一部として
result
を指定しないでください。
register
オプションで有効なレジスタは,r0
から
r25
までの汎用レジスタと,f0
から
f30
までの浮動小数点レジスタです。
preserved (register-list)
nopreserve (register-list)
notused (register-list)
notneeded ((lp))
コンパイラは,関数によって使用されるレジスタと使用されないレジスタを区別するとともに,使用されるレジスタは関数呼び出しの間に保存されているかどうかを認識しておく必要があります。
この情報を指定するには,preserved
,nopreserve
,notused
,および
notneeded
のオプションを使用します。
preserved
レジスタは,関数呼び出しの前後で同じ値を保持します。
nopreserve
レジスタは,関数呼び出しの前後で同じ値を保持しているとはかぎりません。
notused
レジスタは,呼び出された関数で使用されることはありません。
notneeded
特性は,特定の項目がこのリンケージを使用するルーチンで必要ないことを示します。
lp
キーワードは,指定された関数を呼び出すときに,リンケージ・ポインタ・レジスタ (r27
) を設定する必要がないことを指定します。
リンケージ・ポインタが必要になるのは,呼び出された関数がグローバルまたは
static
データにアクセスする場合です。
レジスタが必要ないことを指定するのが有効かどうかを判断する必要があります。
preserved
,nopreserve
,notused
のオプションで有効なレジスタは,r0
から
r30
までの汎用レジスタと,f0
から
f30
までの浮動小数点レジスタです。
#pragma linkage
指示文では,ネストした副構造体を含む構造体は,パラメータまたは特殊リンケージを持つ関数のリターン型としてはサポートされません。
関連する特殊リンケージを持つ関数は,共用型を持つパラメータまたはリターン型はサポートしません。
次の特性は,レジスタ
f3
と
f4
の 2 つの要素を含む
simple-register-list
と,レジスタ
r0
とサブリスト (レジスタ
f0
と
f1
を含む) の 2 つの要素を含む
register-list
を指定します。
nopreserve(f3,f4) parameters(r0,(f0,f1))
次の例は,そのような特性を使用するリンケージを示しています。
#pragma linkage my_link=(nopreserve(f3,f4), parameters(r0,(f0,f1)), notneeded (lp))
register-list
のカッコで囲んだ表記法は,引数と
struct
型の関数リターン値を記述します。
この
struct
の各メンバは,単一のレジスタに引き渡されます。
次の例では,sample_linkage
は 2 つのパラメータを指定します。
最初のパラメータはレジスタ
r0
,r1
,および
r2
に引き渡され,2 番目のパラメータは
f1
に引き渡されます。
struct sample_struct_t { int A, B; short C; } sample_struct; #pragma linkage sample_linkage = (parameters ((r0, r1, r2), f1)) void sub (struct sample_struct_t p1, double p2) { } main() { double d; sub (sample_struct, d); }
3.8 #pragma member_alignment 指示文
省略時の設定では,コンパイラは構造体のメンバを自然境界に合わせます。
構造体メンバのバイト合わせを指定する場合は,#pragma [no]member_alignment
プリプロセッサ指示文を使用してください。
このプラグマの構文は次のとおりです。
#pragma member_alignment
[save | restore]
#pragma nomember_alignment
[base_alignment]
save | restore
パック境界合わせを含め,メンバの境界合わせの現在の状態を保管するために,あるいは前の状態をリストアするためにそれぞれ使用できます。
状態の制御は,member_alignment
あるいは
nomember_alignment
を必要とするヘッダ・ファイル,もしくは,すでに設定されている
member_alignment
を含む必要のあるヘッダ・ファイルの作成のために必要になります。
base_alignment パラメータを使用すると,構造体のベース境界合わせを指定できます。 base_alignment には,次のキーワードのいずれかを使用します。
byte
(1 byte)
word
(2 bytes)
longword
(4 bytes)
quadword
(8 bytes)
octaword
(16 bytes)
構造体メンバの自然境界合わせをリストアするには,#pragma member_alignment
を使用します。
#pragma member_alignment
を使用すると,コンパイラは,構造体メンバを次のバイトではなくそのメンバのタイプに合った次の境界に合わせます。
たとえば,int
変数は次のロングワード境界に合わせられ,short
変数は次のワード境界に合わせられます。
#pragma nomember_alignment
を使用すると,構造体メンバをバイト境界合わせに指定します。
pragma pack
指示文では,構造体メンバの境界合わせをバイト,ワード,ロングワード,あるいはクォドワードに指定することができます。
#pragma pack
についての詳細は,3.11 節を参照してください。
#pragma member_alignment
,#pragma nomember_alignment
および
#pragma pack
の各プラグマの設定は,次のプラグマを処理するまで有効です。
3.9 #pragma message 指示文
#pragma message
指示文は,個々の診断メッセージまたは診断メッセージ・グループの発行を制御します。
このプラグマは,メッセージの発行に関する他のどのコマンド行オプションよりも優先します。
#pragma message
指示文の構文は,次のとおりです。
#pragma message
option1
(message-list)
#pragma message
option2
#pragma message ("string")
この形式の
#pragma message
指示文の構文は,次のとおりです。
#pragma message
option1
(message-list)
option1 パラメータは,以下のキーワードのいずれかでなければなりません。
enable
メッセージ・リストで指定したメッセージの発行を有効にします。
disable
メッセージ・リストで指定したメッセージの発行を無効にします。 無効にできるメッセージは,重大度が Warning または Information の場合に限られます。 メッセージの重大度が Error または Fatal の場合,そのメッセージは無効にしようとしても関係なく発行されます。
emit_once
指定したメッセージは,コンパイル時に 1 度だけ出力されます。
メッセージには,コンパイラがその原因となる条件を初めて検出した場合にのみ出力されるものがあります。
コンパイラがその後,プログラムの中で同じ条件を検出しても,メッセージは出力されません。
このようなメッセージには,たとえば言語拡張の使用に関するメッセージがあります。
原因となる条件を検出するたびに毎回このようなメッセージを出力するには,emit_always
オプションを使用します。
Errors と Fatals のメッセージは必ず出力されます。
このようなメッセージに
emit_once
を指定することはできません。
emit_always
条件を検出するたび,毎回メッセージを出力します。
error
指定したメッセージの重大度を Error に変更します。 Error および Fatal メッセージは,重大度をそれより低くすることはできません。 (例外として,メッセージを Error から Fatal に上げ,次に Error に下げることはできますが,Error から下げることはできません。 Warning と Informational については,重大度を自由に変更できます。)
fatal
指定したメッセージの重大度を Fatal に変更します。
informational
指定したメッセージの重大度を Informational に変更します。 Fatal および Error メッセージは重大度を低くすることができないことに注意してください。
warning
message-list 内の各メッセージの重大度を Warning に変更します。 Fatal および Error メッセージは重大度を低くすることができないことに注意してください。
message-list パラメータは,以下のいずれかになります。
注意
省略時は,選択したコンパイラ・モードに対する診断メッセージがすべて発行されます。 ただし,
check
グループは例外であり,メッセージの表示を明示的に有効にしなければなりません。
単一のメッセージ ID (カッコ付きまたはカッコなし)。
メッセージ ID を取得するには,cc
コマンドで
-verbose
オプションを使用します。
単一のメッセージ・グループ名 (カッコ付きまたはカッコなし)。 メッセージ・グループ名は,次のとおりです。
all
コンパイラのメッセージすべて。
alignment
通常と異なる,あるいは効率の悪い整列になっているデータに関するメッセージ。
c_to_cxx
C++ コンパイラでコンパイルすると無効になるか別の意味になる C 機能の使用を通知するメッセージ。
check
正確で移植性があっても,まぎらわしいか保守性がないために,不適切と見なされたコードや操作を通知するメッセージ。
たとえば,if
文でのテスト式としての代入などです。
check
グループは
level5
メッセージを有効にすると定義されます。
nonansi
ANSI 規格外の機能の使用を通知するメッセージ。
defunct
廃止された機能の使用を通知するメッセージ。 これらの機能は,初期の C コンパイラでは受け付けられていましたが,その後言語から削除されたものです。
obsolescent
ANSI C 規格では有効だが,廃止予定で将来の標準バージョンでは言語から削除されると思われる機能の使用を通知するメッセージ。
overflow
オーバフローが発生したり,データの有効性が失われるおそれがある代入やキャストを通知するメッセージ。
performance
実行時の性能が低下するおそれがあるコードを通知するメッセージ。
portable
他のコンパイラやプラットフォームに移植できないおそれがある言語拡張やその他の構造が使われていることを通知するメッセージ。
preprocessor
疑問がある,あるいは移植性がない前処理構造の使用を通知するメッセージ。
questcode
疑問があるコーディングを通知するメッセージ。
check
グループと類似していますが,このグループのメッセージは,単に脆弱なスタイルを示すだけでなくプログラミングのエラーを示す場合が多くなっています。
returnchecks
関数のリターン値に関連するメッセージ。
uninit
初期化されていない変数の使用に関するメッセージ。
unused
使用されていない式,宣言,ヘッダ・ファイル,静的関数,コード・パスに関するメッセージ。
単一のメッセージ・レベル名 (カッコ付きまたはカッコなし)。 メッセージ・レベル名は次のとおりです。
level1
重要なメッセージ。
このグループのメッセージは,#pragma nostandard
がアクティブの場合は表示されないため,レベル 0 のコア・メッセージほど重要ではありません。
level2
中程度に重要なメッセージ。 Compaq の C では,省略時にレベル 2 になります。
level3
あまり重要でないメッセージ。
level4
役に立つ check/portable メッセージ。
level5
それほど役に立たない check/portable メッセージ。
level6
その他の冗長なメッセージ。
#pragma message
の指定にかかわらず,特に指定しなくても有効になっている非常に重要なコンパイラ・メッセージのコアがあることに注意してください。
これは level0 のメッセージと呼ばれ,ヘッダ・ファイルで発生するメッセージをすべて含み,nostandard
と呼ばれるグループで構成されます。
その他のメッセージ・レベルでは,この有効にされたメッセージのコアにメッセージが追加されます。
level0 は変更できません (無効と有効を切り替えたり,重大度を変更したり,emit_once
特性を変更することはできません)。
ただし,アクションによって変更が許可されていれば,level0 のメッセージを個別に変更することはできます。
たとえば,level0 の Warning または Informational を無効にしたり,level0 の Error を Fatal に変更したりすることなどはできます (個別のメッセージに対する変更の制限を参照してください)。
また,あるレベルを有効にすると,それより値の小さいレベルのメッセージもすべて有効になります。
したがって,level3 メッセージを有効にすると,level2 および level1 のメッセージも有効になります。
また,あるレベルを無効にすると,それより値の大きいレベルのメッセージもすべて無効になります。
したがって,level4 メッセージを無効にすると,level5 および level6 のメッセージも無効になります。
メッセージ ID,グループ名,メッセージ・レベルをコンマで区切って,カッコ内に自由に並べたリスト。
この形式の
#pragma message
指示文の構文は,次のとおりです。
#pragma message
option2
option2 パラメータは,次のキーワードのいずれかでなければなりません。
save
どのメッセージが有効 (無効) になっているかという現在の状態を保存します。
restore
どのメッセージが有効 (無効) になっているかという,直前の状態をリストアします。
save
および
restore
オプションは,主にヘッダ・ファイル内で役に立ちます。
3.9.3 #pragma message ("string")
この形式の
#pragma message
指示文は,Microsoft の
#pragma message
指示文との互換性のためのもので,構文は次のとおりです。
#pragma message ("string")
この指示文は,指定された string をコンパイラ・メッセージとして出力します。 たとえば,コンパイラがソース・ファイル内で次のような行に遭遇したとします。
#pragma message ("hello")
すると,コンパイラは,次のように出力します。
cc: Info: a.c, line 10: hello (simplemessage) #pragma message ("hello") ----------------^
この形式のプラグマでは,マクロの置き換えが実行されます。 たとえば,次のような使い方ができます。
#pragma message ("Compiling file " _ _FILE_ _)
#pragma optimize
指示文は,その指示文に続く関数定義の最適化の特性を設定します。
このプラグマを使用すると,通常はコマンド行でコンパイル全体に対して設定する最適化制御オプションを,ソース・ファイル内で個別の関数に対して指定できます。
このプラグマの形式は次のとおりです。
#pragma optimize
settings
#pragma optimize save
#pragma optimize restore
#pragma optimize command_line
save
および
restore
オプションは,現在の最適化の状態 (level, unroll count, ansi-alias setting, intrinsic setting) の保存と復元を行います。
command_line
オプションを使用すると,最適化設定は,コンパイル時にコマンド行オプション
cc
で指定した時点で有効な設定に戻ります。
settings は,以下の値を組み合わせて指定します。
level
level
は,最適化レベルを設定します。
レベルは次のように指定します。
level=
n
ここで,re n は 0 〜 5 の整数です。
0
すべての最適化を無効にします。 代入されていない変数のチェックを行いません。
1
ローカルな最適化と,一部の共通部分式の認識を有効にします。 コール・グラフによって,プロシージャをコンパイルする順序が決まります。
2
level 1
の最適化を含みます。
グローバルな最適化を有効にします。
この最適化には,データフローの分析,コードの移動,強度の軽減,テストの置換,存在期間分割の分析,コードのスケジューリングが含まれます。
3
level 2
の最適化を含みます。
さらにグローバルな最適化を有効にして実行速度を改善します (コード・サイズは増える)。
たとえば,整数の乗算および除算の展開 (シフトを使用),ループの展開,コードの繰り返しによる分岐の削除を行います。
4
level 3
の最適化を含みます。
プロシージャの相互作用の分析と小プロシージャの自動インライン化 (追加コード量は発見的に制限される) を有効にします。
これが省略時のレベルです。
5
level 4
の最適化を含みます。
ソフトウェアのパイプライン化をアクティブにします。
これはループ展開の特別な形式であり,実行時の性能が改善できる場合があります。
ソフトウェアのパイプライン化では,命令スケジューリングを用いてループ内での命令の停止をなくし,展開されていない複数のループに命令を再配置して性能を改善します。
ソフトウェアのパイプライン化の候補になるループは常に,最も内側にあって分岐やプロシージャの呼び出しを含まないループです。
ユーザのプログラムで
level 5
を使用して効果があるかどうかを判断するには,同じプログラムを
level 4
と
level 5
でコンパイルして,プログラムの実行にかかる時間を測定する必要があります。
使用可能なレジスタを使い尽くすようなループのあるプログラムでは,level 5
の方が実行時間が長くなります。
unroll
unroll
設定はループの展開を制御します。
次のように指定します。
unroll=
n
ここで,n
は負でない整数です。
unroll=
n
は,ループ本体を
n
回展開することを意味します。
ここで,n
は
0
〜
16
の数値です。
unroll=0
は,最適化プログラムの省略時の展開回数を使用することを意味します。
unroll
は,レベル
3
以上の最適化で使用します。
ansi-alias
ansi-alias
は,ansi-alias の仮定条件を制御します。
次のいずれかを指定します。
ansi_alias=on
ansi_alias=off
intrinsic
intrinsic
は,intrinsic の認識を制御します。
次のいずれかを指定します。
intrinsics=on
intrinsics=off
setting 句の間と,各句の "=
" の前後のホワイト・スペースはオプションです。
pragma
ではマクロ置換は行われません。
例:
#pragma optimize level=5 unroll=6
使用上の注意
level=0
句がある場合,他の句は指定できません。
#pragma optimize
指示文はファイル範囲で,関数本体の外に記述しなければなりません。
#pragma environment command_line
指示文は,最適化の状態を,コマンド行で指定した状態にリセットします。
#pragma optimize
で最適化状態のいずれかの設定を指定していない場合,その状態は変更されません。関数定義が検出されると,ソース内のその位置で現在設定されている最適化設定を用いてコンパイルが行われます。
関数を
level=0
でコンパイルすると,コンパイラはその関数をインライン化しません。 一般に,関数がインライン化されると,インライン化されたコードは,インライン化される関数に指定された最適化制御ではなく,呼び出し側で有効な最適化制御を用いて最適化されます。
#pragma pack
指示文は,構造体の全メンバに関する境界合わせの制約を変更します。
指示文は,構造体全体に対して作用するため,構造体の定義全体の前に指定しなければなりません。
このプラグマの構文は,次のとおりです。
#pragma pack {n
|
(n) | ( )}
n
は,その後に続く構造体メンバが
n
バイト境界に位置合わせされることを指定する数字 (1,2,4 など) です。
n
に 0 (ゼロ) を指定した場合には,境界合わせは省略時の設定に戻ります。
これは,cc
コマンドの
-Zpn
オプションで設定されている場合があります。
pragma pack
指示文は,Microsoft Visual C++ でサポートしている
push
および
pop
引数もサポートしています。
#pragma pack ( {push | pop}
[,
identifier]
[,
n])
push
および
pop
引数を使用すると,プログラムのコンポーネントまたがって使用する境界合わせの値を保存したり復元したりすることができます。
これにより,境界合わせの指定が異なる場合でも,コンポーネントを単一の変換ユニットに連結できます。
pragma pack
に
push
引数があると,そのたびに現在のパッキング境界合わせの値は内部コンパイラ・スタックに格納されます。
n
の値を指定すると,その値が新しい境界合わせの値になります。
identifier
で任意の名前を指定すると,それが新しい値に関連付けられます。
pragma pack
に
pop
引数があると,そのたびにスタックの先頭の値が取得されて新しい境界合わせの値になります。
空のスタックがポップされた場合,境界合わせの値は省略時の値に戻り,警告が発行されます。
n
の値を指定すると,その値が新しい境界合わせの値になります。
identifier を指定すると,一致する identifier の値が見つかるまで,スタックに格納された境界合わせの値はすべてスタックから削除されます。 identifier に対応する値もスタックから削除され,identifier がプッシュされる直前に有効だった値が新しい境界合わせの値になります。 identifier に一致する値が見つからなければ,境界合わせの値は省略時の値に戻り,警告が発行されます。
pragma pack
の
push
および
pop
引数を使用すると,ヘッダ・ファイルを検出した前と後で,境界合わせの値が確実に同じになるように,ヘッダ・ファイルを記述することができるようになります。
以下に例を示します。
/* File name: myinclude.h */ #pragma pack (push,enter_myinclude) . . (your include file code) . #pragma pack (pop,enter_myinclude) /* End of myinclude.h */
この例では,現在の境界合わせの値が識別子の
enter_myinclude
に関連付けられ,ヘッダ・ファイルの処理の前にプッシュされます。
次に,インクルード・ファイルのコードが処理されます。
インクルード・ファイルの処理が完了すると,ヘッダ・ファイルの末尾にある
#pragma pack
が,ヘッダ・ファイル内で発生する可能性のある中間の境界合わせ値と,enter_myinclude
に対応する境界合わせの値を削除して,ヘッダ・ファイルの前と後で境界合わせの値が同じになるようにします。
push
および
pop
引数を使用して,現プログラムコードの設定と異なる境界合わせの値を設定するようなヘッダ・ファイルをインクルードすることもできます。
以下に例を示します。
#pragma pack (push,before_myinclude) #include <myinclude.h> #pragma pack (pop,before_myinclude)
この例では,現在の境界合わせ値の保存,インクルード・ファイルの処理 (境界合わせ値がどうなるかは不明),オリジナルの境界合わせ値の復元と処理することにより,myinclude.h
で発生する可能性のある境界合わせ値の変更から,コードを保護しています。
3.12 #pragma pointer_size 指示文
#pragma pointer_size
指示文は,次の項目に関するポインタ・サイズの割り当てを制御します。
参照
ポインタ宣言
関数宣言
配列宣言
このプラグマの構文は次のとおりです。
#pragma pointer_size { long | short | 64 | 32
} | { save | restore }
long
| 64
コンパイラが別の
#pragma pointer_size
指示文を処理するまでの間,この指示文に続いて宣言されているすべてのポインタ・サイズを 64 ビットに設定します。
short
| 32
コンパイラが別の
#pragma pointer_size
指示文を処理するまでの間,この指示文に続いて宣言されているすべてのポインタ・サイズを 32 ビットに設定します。
save
| restore
それぞれ,現在のポインタ・サイズの保管,および保管されているポインタ・サイズのリストアを行います。
save
および
restore
オプションは,混合ポインタのサポートおよび旧オブジェクトへのインタフェースとなるヘッダ・ファイルの保護のため,特に有用です。
複数のポインタ・サイズ・プラグマでコンパイルされたオブジェクトは,古いオブジェクトと互換性がなく,コンパイラは互換性のないオブジェクトが混在していることを認識できません。
たとえば,次のとおりです。
#pragma pointer_size long /* pointer sizes in here are 64-bits */ #pragma pointer_size save #pragma pointer_size short /* pointer sizes in here are 32-bits */ #pragma pointer_size restore /* pointer sizes in here are again 64-bits */
short ポインタの使用は,Tru64 UNIX システム上の Compaq C++ および Compaq C コンパイラに制限されています。 ルーチンが C プログラミング言語以外の言語で書かれている場合は,プログラムで C++ ルーチンから別のルーチンへ short ポインタを引き渡してはなりません。 また,Compaq C++ では,short ポインタを使用するアプリケーションで,short ポインタから long ポインタへ明示的に変換する必要があります。 まず,short ポインタの使用を検討しているアプリケーションを移植した後,それを分析して,short ポインタを使用することが有益であるかどうかを判断します。 関数定義におけるポインタ・サイズの相違は,関数にとってはそれほどのオーバロードではありません。
C コンパイラは,次の状態のいずれかを検出すると,エラー・レベルの診断メッセージを表示します。
定義されている 2 つの関数の,ポインタ・サイズだけが異なっている。
2 つの関数のリターン型だけが異なっている。
#pragma unroll
指示文は,その後の
for
ループで実行されるループ展開の量を制御します。
この指示文のフォーマットは次のとおりです。
#pragma unroll (unroll-factor)
この指示文は,コンパイラに対して,unroll-factor
引数で指定した回数だけ
for
ループを展開するように指示します。
0
から
255
までの整数の定数。
コンパイラは,指示文に続く
for
ループを,この回数だけ展開します。
値が
0
の場合,指示文は無視され,コンパイラは通常の方法でループの展開回数を判断します。
値が
1
の場合,ループは展開されません。
制御を行うには,指示文を
for
文の直前に置く必要があります。
それ以外の位置に置くと,警告が発行され
pragma
は無視されます。
例
#pragma unroll (1) for (i=0; i<1000; i++) {foo(i);}
#pragma linkage
指示文で特殊リンケージを定義した後は (3.7 節で説明),#pragma use_linkage
指示文を使用して,リンケージを関数に関連付けます
このプラグマの構文は次のとおりです。
#pragma use_linkage
linkage-name (id1, id2, ...)
以前に
#pragma linkage
指示文で定義したリンケージの名前を指定します。
指定したリンケージに関連付ける関数の名前または関数の型の
typedef
名を指定します。
関数の型の
typedef
名を指定すると,その型を用いて宣言した関数または関数へのポインタは,指定されたリンケージを持ちます。
#pragma use_linkage
指示文は,ソース・ファイルで,指定したルーチンを使用したり定義する前に記述する必要があります。
このようにしない場合,予測できない結果が生じます。
次の例は,特殊リンケージを定義して,それをルーチンに対応付けます。 このルーチンは,3 つの整数パラメータをとり,最初のパラメータが引き渡された位置に 1 つの整数値を返します。
#pragma linkage example_linkage (parameters(r16, r17, r19), result(r16)) #pragma use_linkage example_linkage (sub) int sub (int p1, int p2, short p3); main() { int result; result = sub (1, 2, 3); }
この例では,result(r16)
オプションは,関数の結果は通常の位置 (r0
) ではなく,r16
に返されることを示しています。
parameters
オプションは,sub
に引き渡される 3 つのパラメータが
r16
,r17
,および
r19
に渡されることを示しています。
次の例では,関数
f1
と関数の型
t
はどちらもリンケージ
foo
を持ちます。
関数ポインタ
f2
を用いて呼び出すと,特殊リンケージを用いて正しく関数
f1
が呼び出されます。
#pragma linkage foo = (parameters(r1), result(r4)) #pragma use_linkage foo(f1,t) int f1(int a); typedef int t(int a); t *f2; #include <stdio.h> main() { f2 = f1; b = (*f2)(1); }
#pragma weak
指示文は,新たに弱外部シンボルを定義し,新しいシンボルと外部シンボルとを関連づけます。
このプラグマの構文は,次のとおりです。
#pragma weak (secondary-name,
primary-name)
強シンボルと弱シンボルについては,2.8 節を参照してください。