#if #ifdef #if defined 等幾種常用的預處理指令的區別

在寫shader時經常會出現一些預編譯指令比如 #if #ifdef #if defined 等,有的時候會感到困惑,所以決定仔細查一下具體的使用方法,并做一個簡單的測試。

#define

#define 指令用于定義一個宏或者常量
#define 有兩種常用的格式:

  1. #define identifier token-string 定義一個宏,在預編譯時會把所有identifier替換成token-string,可以用更容易理解的名稱去代替一個常量,例如:#define PI 3.1415926
  2. #define identifier( argument0, ..., argumentN-1 ) token-string 定義一個類似函數一樣的宏,例如:#define AREA(area, w, h) (area = w*h);
// #define 的使用 //
#define SOME_MACRO
#define PI 3.141593

定義宏時使用第一種方式,當沒有指定 token-string 時,需要注意的兩點是:

  1. 這個identifier依然是被定義了的,且可以使用#if defined 或 #ifdef 檢測到的
  2. 所有identifier字符都會被移除,或者理解為所有identifier的地方都被替換成空字符串。

詳細信息可以參考 #define文檔

#if

#if 是一個預處理指令,用來控制源文件中哪一部分會被編譯。
格式是: #if condition
簡單來說就是 #if 后面的條件語句(condition)如果執行結果不為0,則該#if語句塊內的代碼會被編譯,否則就不會被編譯。
#elif 和 #else 可以類比為常規的用于判斷條件的關鍵字 else if 和 else,區別是前面加了個#符號,用以表明該指令是在預處理階段執行,而不是運行時執行。最后,在所有判斷結束后需要用 #endif 來作為結尾,用于確定預處理語句的作用范圍。

// #if 的使用 //
#define SOME_MACRO 0
#if SOME_MACRO
    return float4(1,1,1,1);
#else
    return float4(0,0,0,1);
#endif

以上代碼結果返回黑色

// #if 的使用 //
#define SOME_MACRO
#if SOME_MACRO
    return float4(1,1,1,1);
#else
    return float4(0,0,0,1);
#endif

以上代碼會報錯: invalid or unsupported integer constant expression

詳細信息可以參考 #if文檔


#ifdef

#ifdef 用于判斷一個常量或者宏是否被定義
格式是: #ifdef identifier
identifier是一個宏或者常量,可以通過#define指令來定義,如果identifier被定義過,則#ifdef 語句塊內的代碼會被編譯,否則不會被編譯。
#ifdef 只是判斷一個常量或者宏是否被定義,不可以用于表達式判斷,但是#if可以,例如:

#define CONST_VALUE 3
#if CONST_VALUE > 1
    return float4(1,1,1,1);
#else 
    return float4(0,0,0,1);
#endif

#ifdef CONST_VALUE > 1      // 這樣寫會報錯 //

hlsl文檔上的說法是#ifdef這種寫法只是為了兼容以往版本,建議使用defined來判斷,即使用 #if defined(MACRO) 這種形式,接下來就會說到。

These directives are provided only for compatibility with previous versions of the language. The use of the defined operator with the #if directive is preferred.

詳細信息可以參考 #ifdef文檔


#if defined

這是文檔里更推薦的一種寫法
#if defined 和 #ifdef 都可以用來判斷一個宏是否被定義,#if !defined 等同于 #ifndef。

#define SOME_MACRO

// #if defined 的使用 //
#if defined(SOME_MACRO)
    // do something //
#elif defined(OTHER_MACRO)
    // do something else //
#endif

// #ifdef 的使用 //
#ifdef SOME_MACRO
    // do something //
#endif

#ifdef OTHER_MACRO
    // do something else //
#endif


總結

  1. 如果是根據一個宏是否被定義來決定一段代碼要不要執行,建議使用 #if defined(MACRO) 方式
  2. 如果是根據一個表達式的值是否為0來決定一段代碼要不要執行,建議使用 #if condition 方式
  3. #ifdef 用于判斷宏或者常量是否被定義,不用于判斷表達式,#if 可以用于判斷表達式


參考鏈接:

https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-preprocessor

https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-pre-define

https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-pre-if

https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-pre-ifdef

https://stackoverflow.com/questions/3802988/difference-between-preprocessor-directives-if-and-ifdef


測試工程地址:

https://github.com/JasonTheCoderMichael/Preprocessor-Directives

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。