[C#, CSharp] 前置處理指示詞
前置處理指示詞(Preprocessor Directive)
- 前置處理指示詞(Preprocessor Directive):用來指示編譯器如何進行編譯的程式,執行時沒有作用
- 前置處理指示詞的種類:
- 宣告指示詞:#define、#undef
- 條件式編譯指示詞:#if、#elif、#else、#endif
- 診斷指示詞:#error、#warning
- Line指示詞:#line
- 區域指示詞:#region、#endregion
- pragma指示詞:#pragma
- 不可以使用/* */方式註解前置處理指示詞
-
#if A XXX //#elif B // O //XXX // O #elif C /* XXX */ // O /* // X 不可使用此方式註解前置處理指示詞 #else */ // X XXX #endif
-
- 前置處理指示詞的種類:
宣告指示詞
- 宣告指示詞:用來定義或取消定義條件式編譯符號
- 定義一個符號
- #define 符號
- 取消符號定義
- #undef 符號
- #define只能出現在程式的第一個語彙基元之前
- 同一個符號多次定義或是多次取消定義都是合法的
-
#define 符號1 //定義符號 XXX #undef 符號1 //取消定義符號
-
#define 符號2 #define 符號2 // O 多次定義同名符號 #undef 符號2 #undef 符號2 #undef 符號2 // O 多次取消符號定義
- 定義一個符號
條件式編譯指示詞
- 條件式編譯指示詞:條件式包含或排除某段原始碼
- 判斷指定符號是否有定義,有定義就編譯區塊內的程式碼
-
#if 符號1
... //#if區塊的內容
[#elif 符號2]opt
... //#elif區塊的內容
[#elif 符號3]opt
... //#elif區塊的內容
#elseopt
... //#else區塊的內容
#endif - #if和#endif一定要成對出現,#elif及#else則不一定要有
- #if和#endif之間可以沒有#elif或有1個以上#elif
- #if和#endif之間可以沒有#else或1個#else,且不能出現在#elif之前
- 條件式編譯指示詞中條件不成立的區塊,編譯時會被略掉,即使有錯誤的語法也可以通過編譯
-
#define 除錯 #define 測試 #if 除錯 System.Console.WriteLine(" Debug "); // 條件成立,會被編譯 #elif 測試 // 因為#if條件成立,所以不會被編譯 for(int i = 0; (({ // 錯誤語法,因條件不成立,所以不會被編譯 #else // 因為#if條件成立,所以不會被編譯 for(int j = 0; ))} // 錯誤語法,不會被編譯 #endif
-
- 如果#if後面接續的符號有定義,就會將該區塊含入編譯 #elif及#else區塊不會被編譯
- 如果#if後面接的符號沒有定義,則會依序判斷#elif是否成立,成立則將該區塊含入編譯
- 如果#if及#elif後面接續的符號都沒有定義,則將#else所屬區塊含入編譯
- 如果#if及elif後面接續的符號皆無定義且沒有#else,則#if、#endif內的程式碼都不編譯
-
- 逐字字串常值中若出現條件式編譯指示詞,會被視做一般字串處理
-
#define 除錯 #if 除錯 //下面的#else會被視為一般字串,而非條件式編譯指示詞 System.Console.WriteLine(@" deubg #else XXX "); #endif
-
- 註解可能會干擾條件式編譯指示詞
-
#define 除錯 #if 除錯 /* #else //除錯成立時 ⇒ #else會被視為註解 /* */ Console.Write("Hello"); //顯示: Hello #endif
-
#undefine 除錯 #if 除錯 /* #else //else 成立 /* */ Console.Write("Hello"); //顯示: Hello #endif
-
- 判斷指定符號是否有定義,有定義就編譯區塊內的程式碼
診斷指示詞
- 診斷指示詞:產生編譯時期的錯誤(Error)和警告(Warning)
- 產生一個錯誤
- #error 錯誤訊息opt
- 訊息可不加雙引號即會被視為字串
- 產生一個警告
- #warning 警告訊息opt
- 訊息可不加雙引號即會被視為字串
-
#if 除錯版本 #warning 除錯版 #elif 正式版本 #warning 正式版 #else #error 錯誤版本 #endif
- 產生一個錯誤
行號指示詞
- Line指示詞:改變編譯器輸出的行號或檔名
- 改變編譯及除錯時的行號
- #line 新行號
- 可以指定行號,會影響編譯器輸出及除錯
- 只改變行號,不改變程式執行流程
- 可能會造成無法正確除錯
- 很少被使用到
- 通常用於原始程式碼和編譯的程式碼不同的時候,例如以某個縮寫代表某段常用的程式碼,所以編譯前需用程式將縮寫代換成程式碼,而代換後的行號可能和原始程式碼不同
- #line 新行號
- 改變編譯及除錯時的行號及檔案名稱
- #line 新行號 檔名
- 回復或取消之前的行號或檔名設定
- #line default
- 在除錯時隱蔽某段程式碼 ⇒ 該段程式碼仍會被執行
- #line hidden
- 在偵錯時略過後續的程式碼
- 可用來縮小要偵錯的程式碼範圍
- 只影響偵錯,不影響行號及錯誤訊息回報
- 在ASP中可以使用#line hidden來區別程式碼是使用者設計或是自動產生
-
Console.Write("1"); //可以偵錯 #line hidden Console.Write("2"); //偵錯時會略過,但程式碼會被執行 Console.Write("3"); //偵錯時會略過,但程式碼會被執行 #line default Console.Write("4"); //可以偵錯
-
- #line hidden
-
using System; class Program { static void Main(string[] args) { Console.Write("1"); #line 5 #warning 第1次警告 Console.Write("2"); #line 10 #warning 第2次警告 Console.Write("3"); #line 10 "新檔名.cs" #warning 第3次警告 Console.Write("3"); #line hidden #warning 第4次警告 Console.Write("4"); #line default #warning 第5次警告 Console.Write("5"); } }
- 改變編譯及除錯時的行號
區域指示詞
- 區域指示詞:
- 標示出某段程式碼的範圍,並加以描述
-
#region 訊息1opt
...#endregion 訊息2opt -
#region 程式碼開始 Console.Write("程式碼"); #endregion 程式碼結束
- 區域指示詞可以放在條件式編譯指示詞內,也可以含括住編譯指示詞
-
#if 除錯 #region 程式碼開始 // #region不可放在條件式編譯指示詞中間 #endif Console.Write("程式碼"); #endregion 程式碼結束
-
- 區域指示詞不可以和條件式編譯指示詞交叉使用
-
#if 除錯 #region 程式碼開始 // #region不可放在條件式編譯指示詞中間 #endif Console.Write("程式碼"); #endregion 程式碼結束
-
pragma指示詞
- pragma警告指示編譯器啓用或停用特定警告,及產生總和檢查碼(checksum)以便協助ASP .Net程式偵錯
- 啓用特定警告
- #pragma warning restore 警告編號1, 警告編號2, ...
- 停用特定警告
- #pragma warning disable 警告編號1, 警告編號2, ...
- 警告編號請參考:MSDN 編譯器錯誤
- 啓用特定警告