C90爲預處理指令家族帶來一位新成員:#pragma。通常狀況下,你們不多見到它。函數
#pragma的做用是爲特定的編譯器提供特定的編譯指示,這些指示是具體針對某一種(或某一些)編譯器的,其餘編譯器可能不知道該指示的含義又或者對該指示有不一樣的理解,也便是說,#pragma的實現是與具體平臺相關的。
爲了讓你們瞭解#pragma的用法,這裏暫時以HP C Compiler爲例子。HP C編譯器主要運行在HP-UX平臺上,它的通常用法和gcc大體相同,例如要編譯程序:
$cc example.c
若是咱們明確指示編譯器優化代碼,能夠這樣編譯:
$cc +On example.c
其中n能夠是一、二、三、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