具有鏈結的實體,包括名字空間級的變數或函式,都需要分配記憶體,在標頭檔案中定義這樣的實體將導致連線錯誤或者記憶體浪費。所以,應該將所有具有鏈結的實體放入實現檔案。
下面的標頭檔案:
1intmax;
2string hello("
hello, world!");
3void fun()
只要被乙個以上的原始檔所包含,就很容易導致鏈結錯誤,編譯器會報告存在重複符合錯誤。原因很簡單:每個原始檔中,都會定義max、hello和fun的函式體,並分配空間。當進行鏈結的時候,鏈結器將面對多個具有相同名字而且互相在競爭的符號。
解決之道非常簡單——只在標頭檔案中放置宣告即可:
1extern
max;
2extern
string
hello;
3void fun();
而實際的定義則放在乙個實現檔案中。
同樣,不要在同檔案中定義名字空間級的static實體,例如:
1static
intmax;
2static
string hello("
hello, world!");
3static
void fun()
這種對static的錯誤使用比在標頭檔案中只定義全域性實體還要危險。對於全域性實體,至少鏈結器可能會立即發現重複,但是靜態資料和函式的重複是合法的。因此,若在某個標頭檔案中定義了靜態資料和靜態函式,而該標頭檔案要被50個檔案包含,那麼函式體和資料所占用的空間在最終的可執行檔案中會重複50次,造成記憶體浪費。博文**
例外情況:
(1)內聯函式。
(2)函式模版。
(3)類模板的靜態資料成員。
為什麼模板函式的定義也要在標頭檔案裡
對於模板,最重要的一點,就是在定義它的時候,編譯器並不會對它進行編譯,因為它沒有乙個實體可用。只有模板被具體化 specialization 之後 用在特定的型別上 編譯器才會根據具體的型別對模板進行編譯。所以才定義模板的時候,會發現編譯器基本不會報錯,也做不出智慧型提示。但是當它被具體用在乙個類上...
標頭檔案中防止重複定義的巨集
我是個有 潔癖 的人,不願意與警告為伍,哪怕是只有乙個,也會讓我渾身上下都不舒服。在一次整改乙個嵌入式arm工程源 的過程中,乙個編譯告警迷惑了我,費了我不少時間。waring c2207w inventing extern inituartpos main.c line 87 按理說不應該出現這種...
inline函式的定義放在標頭檔案中
inline是加在實現上,就算加在宣告上,編譯器也會忽略掉。內聯展開是在編譯時進行的,只有鏈結的時候原始檔之間才有關係。所以內聯要想跨原始檔必須把實現寫在標頭檔案裡。如果乙個 inline 函式會在多個原始檔中被用到,那麼必須把它定義在標頭檔案中。注意 將函式的定義 之間的部分 放在標頭檔案中是強制...