1. 程式人生 > >標頭檔案與同名原始檔的關係

標頭檔案與同名原始檔的關係

一、標頭檔案尋找路徑

  1,系統自帶的標頭檔案用尖括號括起來,這樣編譯器會在系統檔案目錄下查詢。

  #include <xxx.h>
  2,使用者自定義的檔案用雙引號括起來,編譯器首先會在使用者目錄下查詢,然後在到C++安裝目錄(比如VC中可以指定和修改庫檔案查詢路徑,Unix和Linux中可以通過環境變數來設定)中查詢,最後在系統檔案中查詢。
  #include “xxx.h”
二、標頭檔案如何來關聯原始檔
    這個問題實際上是說,已知標頭檔案“a.h”聲明瞭一系列函式,“b.cpp”中實現了這些函式,那麼如果我想在“c.cpp”中使用“a.h”中宣告的這些在“b.cpp”中實現的函式,通常都是在“c.cpp”中使用#include “a.h”,那麼c.cpp是怎樣找到b.cpp中的實現呢?
    其實.cpp和.h檔名稱沒有任何直接關係,很多編譯器都可以接受其他副檔名。比如偶現在看到偶們公司的原始碼,.cpp檔案由.cc檔案替代了。
    在Turbo C中,採用命令列方式進行編譯,命令列引數為檔案的名稱,預設的是.cpp和.h,但是也可以自定義為.xxx等等。
    譚浩強老師的《C程式設計》一書中提到,編譯器預處理時,要對#include命令進行“檔案包含處理”:將file2.c的全部內容複製到#include “file2.c”處。這也正說明了,為什麼很多編譯器並不care到底這個檔案的字尾名是什麼----因為#include預處理就是完成了一個“複製並插入程式碼”的工作。
    編譯的時候,並不會去找b.cpp檔案中的函式實現,只有在link的時候才進行這個工作。我們在b.cpp或c.cpp中用#include “a.h”實際上是引入相關宣告,使得編譯可以通過,程式並不關心實現是在哪裡,是怎麼實現的。原始檔編譯後成生了目標檔案(.o或.obj檔案),目標檔案中,這些函式和變數就視作一個個符號。在link的時候,需要在makefile裡面說明需要連線哪個.o或.obj檔案(在這裡是b.cpp生成的.o或.obj檔案),此時,聯結器會去這個.o或.obj檔案中找在b.cpp中實現的函式,再把他們build到makefile中指定的那個可以執行檔案中。
    在Unix下,甚至可以不在原始檔中包括標頭檔案,只需要在makefile中指名即可(不過這樣大大降低了程式可讀性,是個不好的習慣哦^_^)。在VC中,一般情況下不需要自己寫makefile,只需要將需要的檔案都包括在project中,VC會自動幫你把makefile寫好。

    通常,編譯器會在每個.o或.obj檔案中都去找一下所需要的符號,而不是隻在某個檔案中找或者說找到一個就不找了。因此,如果在幾個不同檔案中實現了同一個函式,或者定義了同一個全域性變數,連結的時候就會提示“redefined”。

請問C語言標頭檔案.h和.c的關係


如果在C檔案(比如miset.c)中定義了一個函式,在其相應的h檔案(miset.h)中宣告,那為什麼在其他檔案中只要include該h檔案(miset.h)時就能找到該函式呢,同時如果把這個函式的宣告放在另外一個頭檔案miphone.h中,而在包含該標頭檔案miphone.h時為什麼又找不到該函式呢。標頭檔案和C檔案時如何一一對應起來的呢?為什麼該C檔案定義的函式宣告只能放在和他名字一樣的標頭檔案中?求教

回覆於: 2011-07-15 18:50:55

其實這一切都有整合開發工具幫你做了。

如果用make命令來自己控制編譯過程,事情很明白了。

比如aaa.h 和 aaa.cpp 定義了函式 int test(void)
mian.cpp 含有對test函式的引用。


首先編譯每一個.cpp檔案,生成對應的.obj檔案。
 在編譯的過程中對於呼叫的函式並不需要具體的實現,只要知道函式的原型即可,在函式呼叫的地方生成一個引用符號。

連結的時候需要找到引用符號的實現。
 link main.obj aaa.obj 此時編譯器要在main.obj、aaa.obj中查詢test的實現。
  如果只 link main.obj 此時編譯器會提示一個錯誤找不到test符號什麼的。
  編譯和連結的過程由整合開發環境自動生成。
  
標註庫檔案只需要引用標頭檔案,連結的時候編譯器自動查詢對應的.lib
自己的庫,不但在原始碼中包含標頭檔案,在連結時還要指明庫檔案。


回覆於: 2011-07-15 23:24:27

1樓有一個小錯誤,就是link過程是由連結器完成的。make只針對一個編譯單元(.c),對其中的預處理後編譯。這個過程中.h會在引用處直接展開。make不需要知道檔案之間更多的關係。連結過程中,連結器會根據引用的函式原型,去尋找函式的實現,並把它們聯絡起來。

回覆於: 2011-07-19 11:46:30

c檔案與h檔案沒有直接聯絡,h檔案宣告符號,c檔案定義符號。在編譯的過程中,編譯器只檢視符號宣告,在連結過程中,連結器查詢符號定義。所以,你編譯程式時只需要引用標頭檔案,你在連結的時候,你要提供obj檔案。

另外你說無法找到函式定義,是因為你沒有提供能夠找到函式定義的obj檔案。無論在哪裡宣告,在連結的時候,只要你提供含有函式定義的obj、lib檔案,都可以進行編譯連結,檔名之間沒有直接的聯絡!

不知道你懂了沒有?

這本書建議有半年以上程式設計經驗之後再看,內容較深,但對除錯程式有很多好處。

引用 13 樓 wtbike 的回覆:
引用 8 樓 zhao4zhong1 的回覆:
《程式設計師的自我修養——連結、裝載與庫》


這本書看得雲裡霧裡的,不過確實能夠明白點東西~~

總結

c檔案和h檔案沒有必然關係,兩個檔名可以不同名,h檔案也能宣告c檔案中的函式,然後在main中包含h檔案,然後使者h中宣告的函式。

但前提是Makefile中有生成c檔案對應o檔案的規則,因為在連結成目標的時候,通過在指定目錄中按照函式標識在o檔案中尋找的。