天天看點

#pragma once 與#ifndef,#define,#endif的差别 、重複定義等相關問題

今天寫程式時,對編譯預處理和#pragma once,#ifndef,#define,#endif産生了一些困惑,以前都是知道個大概,今天一下子查了很多資料,下面就是一些我現在對這個問題的認識,弄清楚這些,再加上我轉的一篇.h和.cpp差別的部落格,對于認清重定義,預處理幫助很大

.cpp檔案是一個編譯單元,obj檔案是編譯的輸出檔案,連結是将所有地obj檔案連結起來組成一個exe。連結過程中如果有不同的cpp檔案中包含相同的函數名,變量名(注意不包括變量的引用、函數的聲明、以及static函數和變量),連結将會報重複定義的錯誤,很多時候如果把函數和變量的定義寫在.h檔案,多個cpp包含此.h檔案,就極可能會發生這樣的錯誤,是以應該把函數的實作、變量的定義寫在.cpp中,在.h中聲明。這裡有一種情況是例外,就是模闆函數,其實STL容器的源碼實作就都寫在.h中,那是因為模闆有模闆的機理,在這裡就不展開了。

上述是在發生在連結時期的重定義,是指兩個或多個cpp之間有沖突的變量和函數,是連結時發現的。還有一種重定義可能會發生在編譯時期。在同一個編譯單元,也就是cpp中,多數cpp可能存在嵌套包含,一個頭檔案被一個cpp包含了兩次,不僅造成編譯效率降低,而且如果此頭檔案中含有定義,那就會被重定義。而#pragma once 與,#ifndef,#define,#endif就是這個問題的解決辦法。但兩者之間又有一些小差別:

1,、 #pragma once是和檔案綁定的,有檔案标志,編譯時會檢查頭檔案有沒有被編譯過,而不用進入檔案中檢查。編譯效率會比預處理頭方法高,但如果程式中有同一個.h檔案的多個副本,一個cpp不慎包含了多個副本.h檔案,那麼#pragma once對此是失效的,因為他隻認檔案不認代碼。

2、#ifndef,#define,#endif是和宏綁定的,編譯時編譯器會進入頭檔案中,檢查宏有沒有被定義,雖然效率比不上#pragma once,但上面 #pragma once失效的情況,在這裡不會發生。此外使用#ifndef要防止多個.h檔案的宏重名,也很煩。

3、#pragma once由編譯器提供保證,是平台相關的,而#ifndef,#define,#endif是語言支援的,是以移植性好于#pragma once,但目前看來#pragma once似乎移植起來也基本沒什麼問題。

4、有方法把這兩種方法結合起來用,但看起來并沒有什麼卵用,反而增加了代碼閱讀者的困擾

繼續閱讀