#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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.