點擊上方藍色字體了解更多的嵌入式編程實用技能。
如果你覺得該文章對你有幫助,歡迎點贊+關注
對于C/C++語言來說,頭文件的設計體現了大部分的系統設計。不合理的頭文件布局是編譯時間過長的根因,不合理的頭文件實際上是不合理的設計。
在本篇文章中,我們將討論C語言中頭文件包含的一些最佳實踐和原則,即頭文件地包含順序。
當在編寫程序時,頭文件的包含順序非常重要。正確的頭文件包含順序可以確保代碼的正確性、可讀性和可維護性。
頭文件大概可以分以下幾類:
系統頭文件:例如stdio.h、stdlib.h等。這些頭文件包含了C語言的基本函數和類型定義。
第三方庫頭文件:這些頭文件通常提供了非系統頭文件庫中定義的函數和數據結構的聲明,即大部分開源代碼。
自定義頭文件:這些頭文件應該包含您自己編寫的函數、結構和宏的聲明。
關于頭文件包含順序有以下方面的討論:
《Google C++ 編程風格指南》中關于頭文件的包含順序規則
C標準庫 –> C++標準庫 –> 第3方庫的頭文件 –> 自己工程的頭文件。如果是cpp文件最先包含的是首選的頭文件,即例如a.cpp文件中應該優先包含a.h,首選的頭文件是為了減少隱藏依賴。
其目的是:為了減少隱藏依賴,同時頭文件和其實現文件匹配,應該先包含其首選項(即其對應的頭文件)。
《C++編程思想》中關于頭文件的包含順序規則
頭文件被包含的順序是從“最特殊到最一般”。順序應該是這樣的:
在本地目錄的任何頭文件 –> 所有“工具”頭文件 –> 第3方庫頭文件 ->標準C++/C庫頭文件
其目的是:保證.h文件的組成部分不被它自身解析(parse),這可以避免潛在的使用錯誤。因為被自身解析缺乏明確提供的聲明或定義。在.c文件的第一行包含.h 文件能確保所有對于構件的物理界面重要的內部信息塊都在.h中,如果的確是缺少了某些信息塊,一旦編譯這個.c文件時就可以發現這個問題。
他們的的不同觀點在于:頭文件的包含順序不同
//?Google?C++?編程風格指南
#include?"math.h"??//?標準庫
#include?"xxx/log.h"???//?三方庫
#include?"xxxx.h"????//?模塊庫
//?C++編程思想
#include?"xxxx.h"????//?模塊庫
#include?"xxx/log.h"???//?三方庫
#include?"math.h"??//?標準庫
《Google C++ 編程風格指南》和《C++編程思想》倡導的包含頭文件的順序各有優點,《Google C++ 編程風格指南》應該能大量減少隱藏的頭文件依賴,而《C++編程思想》則很容易讓你清楚知道你所定義的接口是否和系統庫及第三方庫發生沖突。
《Google C++ 編程風格指南》的優點:符合了從一般到特殊的順序,先打地基再蓋房子的思路比較容易理解。
《C++編程思想》的優點:符合了從特殊到一般的順序。而且這種順序能夠暴露出你的庫的頭文件是不是包含了所有必需的頭文件,如果某個你的庫文件沒有包含它必需的系統文件的話,那么這個順序就會導致編譯錯誤。為什么要暴露這種問題呢?是因為希望“如果用戶只使用你的庫里提供的函數,那么他只需包含你的庫頭文件即可,你的頭文件會自己去包含所需頭文件”,可以方便用戶,否則用戶怎么會知道你的庫依賴啥文件呢?
不管是使用哪一種方式,盡量都要保持一致即可。
如編譯依賴。若x.h包含了y.h,則稱作x依賴y。依賴關系會進行傳導,如x.h包含y.h,而y.h又包含了z.h,則x通過y依賴了z。依賴將導致編譯時間的上升。雖然依賴是不可避免的,也是必須的,但是不良的設計會導致整個系統的依賴關系無比復雜,使得任意一個文件的修改都要重新編譯整個系統,導致編譯時間巨幅上升。
在一個設計良好的系統中,修改一個文件,只需要重新編譯數個,甚至是一個文件。
某產品曾經做過一個實驗,把所有函數的實現通過工具注釋掉,其編譯時間只減少了不到10%,究其原因,在于A包含B,B包含C,C包含D,最終幾乎每一個源文件都包含了項目組所有的頭文件,從而導致絕大部分編譯時間都花在解析頭文件上。
下面是參考了“華為的C語言編程規范”的頭文件規范內容的整理,參考該規范,如何合理地規劃頭文件。
代碼編程規范-擴展(頭文件)