另一篇:.c文件和.h文件的關系
引言:
我們經常在c工程中發現,源文件中要包含自己的頭文件。一直以來,都不知道為什么這樣做。現在,我知道了。
以前的認知:
我認為,.c文件沒有必要包含自己的.h文件。.h文件包含.c文件中定義的函數和全局變量的聲明,.h文件就是.c文件提供的對外接口文件。既然.h文件就是.c文件提供的對外接口文件,那么.c文件就沒必要包含自己的.h文件了(.h文件是對外提供用的,對內又何必再包含進來呢)。
鑒於這樣的理解,我對於工程中.c源文件包含自己的.h頭文件很是不理解,不知道為什么要這樣做。
現在對此的理解:
但是現在,我知道為什么要源文件包含自己的頭文件了。
如下,一段書中的原話:
“如果希望讓編譯器檢查聲明的一致性,一定要把全局聲明放到頭文件中。特別是,永遠不要把外部函數的原型(也就是函數聲明)放到.c文件中:通常它與定義的一致性不能得到檢查,而矛盾的原型(也就是函數聲明)比不用還糟糕。”
注意:外部函數的原型,就是外部函數的聲明。
對這段話的理解:
為什么:“永遠不要把外部函數的原型放到.c 文件中”
這個外部函數A指的是B.c文件之外定義的函數,B.c文件中需要使用外部函數A,就需要先對外部函數A聲明(對外部函數的聲明就是外部函數原型)。對這個外部函數A的聲明,不能放在B.c文件里面來實現。
以實例說明:
①假若工程中有2個源文件a.c和b.c;a.c的頭文件為a.h,b.c的頭文件為b.h。
②a.c中定義了一個函數sum。
③b.c要引用sum這個函數。做法是:在b.c中聲明sum這個函數。然后b.c就可以使用sum函數了。
這樣的做法就是把外部函數sum的聲明放到了b.c中來。然而,這樣的做法很不妥。
不妥的原因:
sum是在a.c中定義的,而聲明確是在b.c中,sum函數的定義和聲明不是在同一個文件中的。定義和聲明不在同一個文件中,編譯的時候,編譯器就不能對定義和聲明的一致性進行檢查。這樣,如果sum的定義和聲明不一致,編譯器就無法檢查出來(定義和聲明不在同一個文件中),那么編譯的時候不會報錯,但是程序運行的時候就可能會出錯。而這樣的錯誤,查找起來又不是很容易。
鑒於此,才這樣說:“永遠不要把外部函數的原型放到.c文件中”。
那如何才能讓編譯器檢查定義和聲明的一致性呢?
前面說,如果把外部函數的原型放到.c文件中,編譯器就無法檢查聲明和定義的一致性(聲明和定義不在同一個文件中)。那么,要讓編譯器檢查定義和聲明的一致性呢,自然是把定義和聲明放在同一個文件中,而如何實現把定義和聲明放在同一個文件里呢?
答案:源文件定義的函數,在源文件對應的頭文件中聲明,然后源文件包含自己的頭文件。這樣定義和聲明就放在同一個文件里了。
援引上述例子:a.c中定義了函數sum,而函數本質上是外部的,函數sum是可以被其它源文件調用的。那么,我們把sum函數的聲明放在a.h中。然后a.c源文件還要包含自己的頭文件,也就是a.h文件。而b.c文件要引用sum函數,就直接包含a.h文件就可以。
sum函數的定義在a.c中,聲明是在a.h中,但是由於a.c包含了a.h,所以sum的定義和聲明就是在同一個文件a.c中了。這樣,編譯器編譯的時候,就能對sum函數定義和聲明的一致性做檢查,如果不一致,就會報錯。
至於其他源文件引用這個外部函數sum,不再采用直接聲明的方式,而是通過包含a.h頭文件的方式。
這樣,編譯器檢查了sum函數定義和聲明的一致性沒有報錯,也就表明a.c中sum函數的定義和a.h中sum函數的聲明是一致的。那么其他源文件都是通過直接包含a.h,來使用函數sum,就也保證了sum函數聲明和定義的一致性了。
結論
c源文件要包含自己的頭文件,目的就是讓編譯器檢查定義和聲明的一致性。
轉自:https://blog.csdn.net/khwkhwkhw/article/details/49798985