#pragma與_Pragma

  C90爲預處理指令家族帶來一位新成員:#pragma。一般情況下,大家很少見到它。
       #pragma的作用是爲特定的編譯器提供特定的編譯指示,這些指示是具體針對某一種(或某一些)編譯器的,其他編譯器可能不知道該指示的含義又或者對該指示有不同的理解,也即是說,#pragma的實現是與具體平臺相關的。
       爲了讓大家瞭解#pragma的用法,這裏暫時以HP C Compiler爲例子。HP C編譯器主要運行在HP-UX平臺上,它的一般用法和gcc大致相同,例如要編譯程序:
       $cc example.c
       如果我們明確指示編譯器優化代碼,可以這樣編譯:
       $cc +On example.c
       其中n可以是1、2、3、4,分別代表不同程度的優化,例如:
       $cc +O2 example.c
       這條命令指示HP C編譯器對整個example.c的代碼採取第2級別的優化編譯。
       但是,某種情況下我們可能需要特殊對待某一部分的代碼,譬如暫停優化,HP C編譯器提供幾種途徑去實現,其中之一是使用#pragma:
       //prog.c
       void f(){...}
       #pragma OPTIMIZE OFF
       int g(){...}
       #pragma OPTIMIZE ON
       double h(){...}
       $cc +O2 prog.c
       上面的prog.c中有3個函數,我們想用第2級別的優化編譯代碼整個文件。惟獨函數g()例外,我們出於某種考慮決定不對它進行任何優化,可以看到,用兩條#pragma指令就能夠達到目的。
       第一條#pragma指令指示編譯器停止優化代碼,於是g()的代碼是沒有經過優化的。第二條#pragma指令通知編譯器重新開始代碼的優化編譯(優化級別仍然是先前命令行給出的level 2),所以從h() 開始的代碼又都是經過優化的。
       這裏以代碼的優化編譯爲例簡單介紹了#pragma的用法,讀者必須記住:具體的#pragma指令在不同情況下可能有不同的效果。假設有兩家廠商各自推出自己的C編譯器,可能真會這麼巧同時使用相同的#pragma指令,偏偏它們的實現又不相同,這樣編譯的代碼就可能會出現意想不到的結果。所以,爲了保證#pragma指令能夠被正確的解釋,我們通常需要利用其他的預處理指令給予配合,例如:
       ...
       #ifdef __hpux
              #pragma FLOAT_TRAPS_ON _ALL
       #endif
       ...
       上例中,只有定義“__hpux”宏的HP C編譯器纔會看到#pragma指令,其他編譯器,例如gcc,根本不會看到它的,因爲gcc不會去定義“__hpux”宏,所以早在預處理階段,#pragma指令的內容就被預處理程序刪掉了。
       有人可能會問:如果萬一編譯器看到它不認識的#pragma指令會報錯嗎?
       答案是:不會。
       具體到某一條#pragma指令的涵義不是C標準的管轄範圍,編譯器不能夠因爲看到不認識的#pragma指令就說程序有錯,惟一的做法是忽略它。
       例如:
       /*Example C code*/
       #pragma UNKNOWN_DIRECTIVE UNKNOWN_OPTION
       int main(void)
       {
              return 0;
       }
       $gcc test.c
       $./a.out
       $
        儘管gcc不認識上面代碼中的#pragma指令,但編譯test.c是完全沒有問題的。
       現在,C99提供新的關鍵字“_Pragma”完成類似的功能,例如:
       #pragma OPTIMIZE OFF
       在C99中可以寫成:
       _Pragma(“OPTIMIZE OFF”)              //注意:語句後面是沒有分號的
       “_Pragma”比“#pragma”(在設計上)更加合理,因而功能也有所增強。
       例如,我們的編譯器支持4個不同程度的優化等級,如果使用#pragma,則這樣寫:
       #pragma OPT_LEVEL n //1≤n≤4
    你會不會覺得每次都要重複寫“#pragma...”很麻煩?如果可以利用宏定義來簡化書寫就好了:
    #define OPT_L(x) #pragma OPT_LEVEL x
    這時我們只須寫:
    OPT_L(3)
    就相當於寫:
    #pragma OPT_LEVEL 3
    可惜,在C90裏這永遠是一個夢想!因爲字符“#”在預處理指令中有特殊的用途,跟在它後面的必須是宏的參數名,例如:
    #define MACRO(x) #x
    那麼,MACRO(example)的替換結果爲:
    “example”
       可以想象,前面通過#define來定義一個關於#pragma的宏是不可行的。
       不過,新的關鍵字“_Pragma”就很好的解決了問題,由於_Pragma並不能有字符“#”,所以我們可以放心的定義宏:
       #define OPT_L(X) PRAGMA(OPT_LEVEL X)
       #define PRAGMA(X) _Pragma(#X)
       這時,我們只要寫:
       OPT_L(2)
       經過預處理後,就成爲:
       _Pragma(“OPT_LEVEL 2”)
       即:
       #pragma OPT_LEVEL 2
 
發佈了27 篇原創文章 · 獲贊 0 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章