Pragma ディレクティブと __pragma キーワードと _Pragma キーワード

Pragma ディレクティブは、マシン固有またはオペレーティング システム固有のコンパイラ機能を指定します。 #pragmaで始まる行は、pragma ディレクティブを指定します。 Microsoft 固有の __pragma キーワードを使用すると、マクロ定義内でディレクティブ pragma コーディングできます。 C99 で導入され、C++11 で採用されている標準の _Pragma プリプロセッサ 演算子も同様です。

構文

#pragmatoken-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 ディレクティブを認識します。

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;
}

関連項目

C/C++ のプリプロセッサ リファレンス
C pragma ディレクティブ
キーワード