.NET Visual C#言語入門 > プリプロセッサ ディレクティブ
のぶ亭『プログラミングの相談窓口』 … 様々なプログラミング問題を個別対応致します |
プリプロセッサ ディレクティブ
プリプロセッサ・ディレクティブ(preprocessor directive)を用いることで、ソースコードに対して、条件付きコンパイル、エラーや警告の通知、アウトライン表示などを行うことが出来ます。
C言語でのプリプロセッサ・ディレクティブは、コンパイル前に独立した「プロプロセッサ」により、コンパイルするためのソース・コードを生成していました。C#では、独立はしていませんが、C言語同様の処理が行われます。
C#は、C,C++で採用されている、インクルードファイル(外部ファイルの挿入)やマクロには対応していません。
目次
概要
C#のプリプロセッサ・ディレクティブは、全て #
から始まります。
シンボル定義
- #define
- #undef
条件付きコンパイル
- #if
- #else
- #elif
- #endif
エラー、警告の報告
- #warning
- #kerror
- #line
アウトライン表示
- #region
- #endregion
プラグマ (Ver. 2.0)
- #pragma
- #pragma warning
- #pragma checksum
シンボル定義・未定義
#ifディレクティブで使用するシンボルの定義を行います。未定義状態にすることもできます。
シンボルの定義 #define DEBUG シンボルの未定義 #undef DEBUG
- シンボルを使用して、コンパイル条件を指定できます。
- シンボルを定義することはできますが、シンボルに値は代入できません。
- #define ディレクティブは、ファイルの先頭で、ディレクティブやそれ以外の命令よりも前に記述する必要があります。
- シンボルは /define コンパイラ オプションでも定義できます。
- #undef を使うと、シンボルを未定義状態にできます。
- /define または #define で定義されたシンボルは、同じ名前の変数とは競合しません。
- 変数名をプリプロセッサ・ディレクティブに渡すことはできません。
- シンボルはプリプロセッサ ディレクティブだけで評価されます。
- #define で定義されたシンボルのスコープは、シンボルが定義されたファイル内だけです。
- #define の使用例については、「コンパイル条件」を参照してください。
条件付きコンパイル
条件付きコンパイルとは、シンボルを定義し、#if~#
#elif~#else~#endifディレクティブを用いることで、
コンパイル対象の範囲を指定することができます。
#elif、#elseディレクディブは省略できます。
#
#if シンボルA ソースコード行 // シンボルAがtrueの時の有効なソースコード行 #elif シンボルB ソースコード行 // シンボルBがtrueの時の有効なソースコード行 #else ソースコード行 // 上記以外の時の有効なソースコード行 #endif
#if を使用すると、条件付ディレクティブが実行され、1つ以上のシンボルについて true か評価します。シンボルが true と評価された場合は、#if とこれに最も近い #endif ディレクティブの間にあるすべてのコードが、コンパイラによって評価されます。
複数のシンボルを評価する場合、== (等値)、!= (非等値)、&& (AND)、および || (OR) の演算子が使用できます。シンボルと演算子は、かっこを使用してグループ化できます。
- #if を、#else、#elif、#endif、#define、#undef ディレクティブと組み合わせて使用すると、1 つ以上のシンボルの条件に従って、コードを処理対象にしたり、処理対象から外したりできます。
- #if は、デバッグ・ビルド用にコンパイルするときや、特定の構成でコンパイルするときに使用すると便利です。
- #if で始まる条件付きディレクティブは、#endifディレクティブで明示的に終了する必要があります。
- #define を使用すると、シンボルを定義できます。定義したシンボルを式として #if ディレクティブに渡すと、式は true と評価されます。
- シンボルは /define コンパイラ オプションでも定義できます。
- #undef を使うと、シンボルを未定義状態にできます。
- /define または #define で定義されたシンボルは、同じ名前の変数とは競合しません。
- 変数名をプリプロセッサ・ディレクティブに渡すことはできません。
- シンボルはプリプロセッサ・ディレクティブだけで評価されます。
- #define で定義されたシンボルのスコープは、シンボルが定義されたファイル内だけです。
// preprocessor_if.cs #define DEBUG #define VC_V7 using System; public class MyClass { static void Main() { #if (DEBUG && !VC_V7) Console.WriteLine("DEBUG is defined"); #elif (!DEBUG && VC_V7) Console.WriteLine("VC_V7 is defined"); #elif (DEBUG && VC_V7) Console.WriteLine("DEBUG and VC_V7 are defined"); #else Console.WriteLine("DEBUG and VC_V7 are not defined"); #endif } }
エラー、警告の報告
#warning コードの特定の位置でレベル 1 警告を表示します。 #error コードの特定の位置でエラーを表示します。 #line エラーや警告で出力するコンパイラの行番号とファイル名 (省略可能) を強制的に変更します。
#warning
一般に、条件付きディレクティブ内で使用します。
// preprocessor_warning.cs // CS1030 expected #define DEBUG class MainClass { static void Main() { #if DEBUG #warning DEBUG is defined #endif } }
#error
一般的に、条件付きディレクティブ内で使用します。
// preprocessor_error.cs // CS1029 expected #define DEBUG class MainClass { static void Main() { #if DEBUG #error DEBUG is defined #endif } }
#line
#line ディレクティブは、ビルド プロセスの、自動化された中間ステップで使われる場合があります。たとえば、元のソース コード ファイルから行を削除した場合でも、コンパイラがファイル内での削除前の行番号のままで出力を生成できるように、行を削除してから #line を指定して、削除前の行番号指定をシミュレートします。
#line hidden ディレクティブは、後続の行をデバッガから隠します。これで、開発者がコードをステップ実行するときに、#line hidden から次の #line ディレクティブ (もう 1 つの #line hidden ディレクティブでないことが前提) までのすべての行がステップ オーバーされます。このオプションを ASP.NET で使用すると、ユーザー定義のコードとコンピュータが生成したコードを区別できます。この機能は主に ASP.NET で使用されますが、より多くのソース ジェネレータで利用される可能性があります。
#line hidden ディレクティブは、エラー報告のファイル名や行番号には影響しません。このため、隠ぺいされたブロック内でエラーが検出された場合、コンパイラは現在のファイル名とエラーの行番号を報告します。
#line filename ディレクティブにより、コンパイラ出力に表示するファイル名が指定されます。既定では、ソース コード ファイルの実際の名前が使われます。ファイル名は、二重引用符 ("") で囲みます。
ソース コード ファイルには、任意の数の #line ディレクティブを指定できます。
例1
この例は、2 つの警告の行番号がどのように報告されるかを示しています。#line 200 ディレクティブは、行番号を強制的に 200 に設定します。既定の行番号は 7 です。既定の #line ディレクティブの結果として、他の行 (#9) は通常の行番号になります。
class MainClass { static void Main() { #line 200 int i; // CS0168 on line 200 #line default char c; // CS0168 on line 9 } }
例2
次の例は、デバッガがどのようにコード内の隠ぺいされた行を無視するかを示しています。この例を実行すると、3 行のテキストが表示されます。ただし、この例で示すようにブレークポイントを設定し、F10 キーを押してコードをステップ実行すると、デバッガは隠ぺいされた行を無視します。また、隠ぺいされた行にブレークポイントを設定しても、デバッガはその行を無視します。
// preprocessor_linehidden.cs using System; class MainClass { static void Main() { Console.WriteLine("Normal line #1."); // Set break point here. #line hidden Console.WriteLine("Hidden line."); #line default Console.WriteLine("Normal line #2."); } }
アウトライン表示
#region コードのブロックを指定し、Visual Studio コード エディタのアウトライン機能を使用します。 #endregion #region ブロックの終了を指定します。
#region ~ #endregion
#region ブロックは、#endregion ディレクティブで終了させる必要があります。
#region ブロックは、#if ブロックとオーバーラップすることはできません。ただし、#region ブロックを #if ブロック内に入れ子にしたり、#if ブロックを #region ブロック内に入れ子にしたりすることはできます。
#region MyClass definition public class MyClass { static void Main() { } } #endregion
プラグマ
#pragma,このキーワードが含まれているファイルに関するコンパイルについて、特殊な命令をコンパイラに指示します。
#pragma warning,特定の警告を有効または無効にします。
#pragma checksum,ASP.NET ページのデバッグに使用するソース ファイルのチェックサムを生成します。
#pragma
#pragma pragma-name pragma-arguments
- pragma-name
- 認識されるプラグマの名前。
- pragma-arguments
- プラグマ固有の引数。
#pragma warning
#pragma warning disable warning-list
#pragma warning restore warning-list
パラメータ
- warning-list
- コンマで区切られた警告番号の一覧。"CS" プレフィックスを付けず、番号だけを入力します。
警告番号を指定しないと、disable ではすべての警告が無効になり、restore ではすべての警告が有効になります。
使用例
// pragma_warning.cs using System; #pragma warning disable 414, 3021 [CLSCompliant(false)] public class C { int i = 1; static void Main() { } } #pragma warning restore 3021 [CLSCompliant(false)] // CS3021 public class D { int i = 1; public static void F() { } }
#pragma checksum
#pragma checksum "filename" "{guid}" "checksum bytes"
パラメータ
- "filename"
- 変更または更新を監視する必要があるファイルの名前。
- "{guid}"
- ファイルのグローバル一意識別子 (GUID: Globally Unique Identifier)。
- "checksum_bytes"
- チェックサムのバイトを表す 16 進形式の文字列。偶数の 16 進数であることが必要です。奇数を使用すると、コンパイル時に警告が出力され、ディレクティブが無視されます。
解説
Visual Studio デバッガは、常に正しいソースを検出することを目的としてチェックサムを使用します。コンパイラはソース ファイルのチェックサムを計算し、プログラム データベース (PDB) ファイルに出力します。デバッガは、その PDB を使用して、ソース ファイルについて算出されたチェックサムとの比較を行います。
この方法は、ASP.NET プロジェクトには使用できません。なぜなら、算出されたチェックサムは .aspx ファイルではなく生成されたソース ファイルを対象としているからです。この問題を解決するため、#pragma checksum により ASP.NET ページのチェックサムがサポートされています。
Visual C# に ASP.NET プロジェクトを作成すると、生成されるソース ファイルには .aspx ファイルのチェックサムが含まれています。ソースは、この .aspx ファイルから生成されます。次に、コンパイラがこの情報を PDB ファイルに書き込みます。
ファイルに #pragma checksum ディレクティブが見つからない場合、コンパイラはチェックサムを計算し、その値を PDB ファイルに書き込みます。
使用例class TestClass { static int Main() { #pragma checksum "file.cs" "{.....-....-....-....-......}" "{0123456789}" } }