Pragma ディレクティブと __pragma
キーワードと _Pragma
キーワード
Pragma ディレクティブは、マシン固有またはオペレーティング システム固有のコンパイラ機能を指定します。 #pragma
で始まる行は、pragma ディレクティブを指定します。 Microsoft 固有の __pragma
キーワードを使用すると、マクロ定義内でディレクティブ pragma コーディングできます。 C99 で導入され、C++11 で採用されている標準の _Pragma
プリプロセッサ 演算子も同様です。
構文
#pragma
token-string
__pragma(
token-string)
2 つの先頭のアンダースコア - Microsoft 固有の拡張機能
_Pragma(
string-literal)
C99
解説
C および C++ の各実装は、そのホスト コンピューターまたはオペレーティング システムに固有の機能をいくつかサポートしています。 たとえば、一部のプログラムは、メモリ内のデータの位置、または特定の関数がパラメーターを受け取る方法を正確に制御する必要があります。 #pragma
ディレクティブにより、各コンパイラが C 言語および C++ 言語の全体的な互換性を維持しながら、コンピューター固有の機能およびオペレーティング システム固有の機能を提供することが可能になります。
Pragma ディレクティブは、定義上、コンピューター固有またはオペレーティング システム固有であり、通常はコンパイラごとに異なります。 pragma は、新しいプリプロセッサ機能を提供するために、条件付きディレクティブで使用できます。 または、1 つを使用して、コンパイラに実装定義の情報を提供します。
token-string は、特定のコンパイラ命令と引数 (存在する場合) を表す一連の文字です。 シャープ記号 (#
) は、pragma を含む行の最初の空白以外の文字である必要があります。 空白文字は、シャープ記号と "pragma" という単語を区切ることができます。 #pragma
の後に、トランスレーターによりプリプロセス トークンとして解析できるテキストを記述します。 #pragma
の引数は、マクロの展開の対象になります。
string-literal は、_Pragma
への入力です。 外部引用符と先頭または末尾の空白は削除されます。 \"
は "
に置き換えられ、\\
は \
に置き換えられます。
コンパイラは、認識できない pragma を検出してコンパイルを続行すると、警告を発行します。
Microsoft C および C++ コンパイラは、次の pragma ディレクティブを認識します。
alloc_text
auto_inline
bss_seg
check_stack
code_seg
comment
component
conform
1
const_seg
data_seg
deprecated
1 C++ コンパイラでのみサポートされています。
Pragma ディレクティブとコンパイラ オプション
一部の pragma ディレクティブの機能はコンパイラ オプションのものと同じです。 ソース コード内で pragma に到達すると、コンパイラ オプションで指定された動作をオーバーライドします。 たとえば、/Zp8
を指定している場合は、コードの特定のセクションのコンパイラ設定を pack
でオーバーライドできます。
cl /Zp8 some_file.cpp
// some_file.cpp - packing is 8
// ...
#pragma pack(push, 1) - packing is now 1
// ...
#pragma pack(pop) - packing is 8 again
// ...
__pragma
キーワード
コンパイラは、Microsoft 固有の __pragma
キーワードもサポートしています。これには、#pragma
ディレクティブと同じ機能があります。 違いは、__pragma
キーワードはマクロ定義でインラインで使用できるということです。 コンパイラはディレクティブ内のシャープ記号 ('#') を文字列化演算子 (#) として解釈するため、#pragma
ディレクティブはマクロ定義では使用できません。
マクロでの __pragma
キーワードの使用方法を次のコード例に示します。 このコードは、「コンパイラ COM サポートのサンプル」の ACDUAL サンプルの mfcdual.h ヘッダーからの抜粋です。
#define CATCH_ALL_DUAL \
CATCH(COleException, e) \
{ \
_hr = e->m_sc; \
} \
AND_CATCH_ALL(e) \
{ \
__pragma(warning(push)) \
__pragma(warning(disable:6246)) /*disable _ctlState prefast warning*/ \
AFX_MANAGE_STATE(pThis->m_pModuleState); \
__pragma(warning(pop)) \
_hr = DualHandleException(_riidSource, e); \
} \
END_CATCH_ALL \
return _hr; \
_Pragma
プリプロセス演算子
_Pragma
は、Microsoft 固有の __pragma
キーワードに似ています。 これは、C99 の C 標準と C++ 11 の C++ 標準に導入されました。 C では、/std:c11
または /std:c17
オプションを指定した場合にのみ使用できます。 C++ の場合は、既定値を含むすべての /std
モードで使用できます。
#pragma
とは異なり、_Pragma
では、pragma ディレクティブをマクロ定義に含めることができます。 文字列リテラルは、#pragma
ステートメントの後に記述する場合以外と同じにする必要があります。 次に例を示します。
#pragma message("the #pragma way")
_Pragma ("message( \"the _Pragma way\")")
上に示すように、引用符と円記号はエスケープする必要があります。 認識されない pragma 文字列は無視されます。
次のコード例は、assert に似たマクロで _Pragma
キーワードを使用する方法を示しています。 これは、条件式が定数である場合に警告を抑制する pragma ディレクティブを作成します。
マクロ定義では、複数ステートメントのマクロに do ... while(0)
イディオムを使用して、1 つのステートメントと同じように使用できるようにします。 詳細については、Stack Overflow に関してC 複数行マクロを参照してください。 この例の _Pragma
ステートメントは、その後のコード行にのみ適用されます。
// Compile with /W4
#include <stdio.h>
#include <stdlib.h>
#define MY_ASSERT(BOOL_EXPRESSION) \
do { \
_Pragma("warning(suppress: 4127)") /* C4127 conditional expression is constant */ \
if (!(BOOL_EXPRESSION)) { \
printf("MY_ASSERT FAILED: \"" #BOOL_EXPRESSION "\" on %s(%d)", __FILE__, __LINE__); \
exit(-1); \
} \
} while (0)
int main()
{
MY_ASSERT(0 && "Note that there is no warning: C4127 conditional expression is constant");
return 0;
}