名前空間
変種
操作

実装定義の動作制御

From cppreference.com

実装定義の動作は#pragmaディレクティブによって制御されます。

目次

[編集] 構文

#pragma pragma_params (1)
_Pragma ( string-literal ) (2) (C99以降)
1) 実装定義の動作をします(pragma_paramsが下記に示す標準プラグマのいずれかである場合を除く)。
2) string-literalからエンコーディングプレフィックス(存在する場合)、外側の引用符、および先頭/末尾の空白を削除し、\""に、\\\に置換してから、結果をトークン化し(翻訳ステージ3と同様)、その結果を(1)#pragmaへの入力として使用します。

[編集] 説明

プラグマディレクティブは、コンパイラ警告の無効化やアライメント要件の変更など、コンパイラの実装固有の動作を制御します。認識されないプラグマは無視されます。

[編集] 標準プラグマ

以下の3つのプラグマは言語標準で定義されています。

#pragma STDC FENV_ACCESS arg (1) (C99以降)
#pragma STDC FP_CONTRACT arg (2) (C99以降)
#pragma STDC CX_LIMITED_RANGE arg (3) (C99以降)

ここでargONまたはOFFまたはDEFAULTのいずれかです。

1) ONに設定されている場合、プログラムが浮動小数点環境にアクセスまたは変更することを示すため、フラグテストやモード変更を損なう可能性のある最適化(例: グローバル共通部分式削除、コード移動、定数畳み込み)が禁止されます。デフォルト値は実装定義であり、通常はOFFです。
2) 浮動小数点式の「契約」を許可します。これは、式が正確に記述されたとおりに評価された場合に観察される丸め誤差や浮動小数点例外を省略する最適化です。たとえば、単一の融合乗算加算CPU命令による(x * y) + zの実装を許可します。デフォルト値は実装定義であり、通常はONです。
3) 複素数の乗算、除算、絶対値が、中間オーバーフローの可能性にもかかわらず、単純化された数学的公式 (x+iy)×(u+iv) = (xu-yv)+i(yu+xv)(x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u2
+v2
)
、および |x+iy| = x2
+y2
を使用する可能性があることをコンパイラに通知します。言い換えると、プログラマは those 関数に渡される値の範囲が制限されていることを保証します。デフォルト値はOFFです。

注: これらのプラグマをサポートしていないコンパイラは、gccの-fcx-limited-range-ffp-contractなどの同等のコンパイル時オプションを提供している場合があります。

[編集] 非標準プラグマ

[編集] #pragma once

#pragma onceは、ほとんどの最新コンパイラでサポートされている非標準プラグマです。ヘッダーファイル内に現れる場合、同じソースファイルに(直接的または間接的に)複数回インクルードされても、一度だけ解析されることを示します。

同じヘッダーの複数インクルードを防ぐための標準的なアプローチは、インクルードガードを使用することです。

#ifndef LIBRARY_FILENAME_H
#define LIBRARY_FILENAME_H
// contents of the header
#endif /* LIBRARY_FILENAME_H */

これにより、任意の翻訳単位でヘッダーが複数回インクルードされても、最初のインクルード以外のすべてはコンパイルから除外されます。すべての最新コンパイラは、ヘッダーファイルがインクルードガードを使用しているという事実を記録し、ガードがまだ定義されている限り(例: gccを参照)、再度遭遇したときにファイルを再解析しません。

#pragma onceの場合、同じヘッダーは次のように表示されます。

#pragma once
// contents of the header

ヘッダーガードとは異なり、このプラグマにより、誤って同じマクロ名を複数のファイルで使用することができなくなります。一方で、#pragma onceではファイルはファイルシステムレベルのIDに基づいて除外されるため、プロジェクト内の複数の場所に存在するヘッダーを2回インクルードした場合に保護することはできません。

[編集] #pragma pack

このプラグマ群は、後続の構造体および共用体メンバーの最大アライメントを制御します。

#pragma pack(arg) (1)
#pragma pack() (2)
#pragma pack(push) (3)
#pragma pack(push, arg) (4)
#pragma pack(pop) (5)

ここでargは2のべき乗の小さい数で、バイト単位の新しいアライメントを指定します。

1) 現在のアライメントを値argに設定します。
2) 現在のアライメントをデフォルト値(コマンドラインオプションで指定)に設定します。
3) 現在のアライメントの値を内部スタックにプッシュします。
4) 現在のアライメントの値を内部スタックにプッシュしてから、現在のアライメントを値argに設定します。
5) 内部スタックのトップエントリをポップしてから、現在のアライメントをその値に設定(復元)します。

#pragma packは構造体のアライメントを低下させる可能性がありますが、構造体をオーバーアラインさせることはできません。

GCCおよびMSVCの特定の詳細を参照してください。

[編集] 参考文献

  • C17標準 (ISO/IEC 9899:2018)
  • 6.10.6 Pragma directive (p: 127)
  • 6.10.9 Pragma operator (p: 129)
  • C11標準 (ISO/IEC 9899:2011)
  • 6.10.6 Pragma directive (p: 174)
  • 6.10.9 Pragma operator (p: 178)
  • C99標準 (ISO/IEC 9899:1999)
  • 6.10.6 Pragma directive (p: 159)
  • 6.10.9 Pragma operator (p: 161-162)
  • C89/C90標準 (ISO/IEC 9899:1990)
  • 3.8.6 Pragma directive

[編集] 関連項目

C++ ドキュメント for 実装定義の動作制御

[編集] 外部リンク

1.  Visual Studio 2019 の C++ プラグマ
2.  GCC が受け付けるプラグマ
3.  個々のプラグマの説明 および IBM AIX XL C 16.1 の標準プラグマ
4.  Sun Studio 11 C++ User's Guide の付録 B. プラグマ
5.  Intel C++ コンパイラ プラグマ
6.  HP aCC コンパイラ プラグマ
English 日本語 中文(简体) 中文(繁體)