簡單的說其實要理解C文件與頭文件(即.h)有什麼不同之處,首先需要弄明白編譯器的工作過程,一般說來編譯器會做以下幾個過程:
1.預處理階段
2.詞法與語法分析階段
3.編譯階段,首先編譯成純彙編語句,再將之彙編成跟CPU相關的二進制碼,生成各個目標文件(.obj文件)
4.連接階段,將各個目標文件中的各段代碼進行絕對地址定位,生成跟特定平臺相關的可執行文件,當然,最後還可以用objcopy生成純二進制碼,也就是去掉了文件格式信息。(生成.exe文件)
編譯器在編譯時是以C文件爲單位進行的,也就是說如果你的項目中一個C文件都沒有,那麼你的項目將無法編譯,連接器是以目標文件爲單位,它將一個或多個目標文件進行函數與變量的重定位,生成最終的可執行文件,在PC上的程序開發,一般都有一個main函數,這是各個編譯器的約定,當然,你如果自己寫連接器腳本的話,可以不用main函數作爲程序入口!!!!
(main .c文件 目標文件 可執行文件 )
有了這些基礎知識,再言歸正傳,爲了生成一個最終的可執行文件,就需要一些目標文件,也就是需要C文件,而這些C文件中又需要一個main函數作爲可執行程序的入口,那麼我們就從一個C文件入手,假定這個C文件內容如下:
#include <stdio.h>
#include "mytest.h"
int main(int argc,char **argv)
{
test = 25;
printf("test.................%d\n",test);
}
頭文件內容如下:
int test;
現在以這個例子來講解編譯器的工作:
1.預處理階段:編譯器以C文件作爲一個單元,首先讀這個C文件,發現第一句與第二句是包含一個頭文件,就會在所有搜索路徑中尋找這兩個文件,找到之後,就會將相應頭文件中再去處理宏,變量,函數聲明,嵌套的頭文件包含等,檢測依賴關係,進行宏替換,看是否有重複定義與聲明的情況發生,最後將那些文件中所有的東東全部掃描進這個當前的C文件中,形成一箇中間“C文件”
2.編譯階段,在上一步中相當於將那個頭文件中的test變量掃描進了一箇中間C文件,那麼test變量就變成了這個文件中的一個全局變量,此時就將所有這個中間C文件的所有變量,函數分配空間,將各個函數編譯成二進制碼,按照特定目標文件格式生成目標文件,在這種格式的目標文件中進行各個全局變量,函數的符號描述,將這些二進制碼按照一定的標準組織成一個目標文件
3.連接階段,將上一步成生的各個目標文件,根據一些參數,連接生成最終的可執行文件,主要的工作就是重定位各個目標文件的函數,變量等,相當於將個目標文件中的二進制碼按一定的規範合到一個文件中再回到C文件與頭文件各寫什麼內容的話題上:理論上來說C文件與頭文件裏的內容,只要是C語言所支持的,無論寫什麼都可以的,比如你在頭文件中寫函數體,只要在任何一個C文件包含此頭文件就可以將這個函數編譯成目標文件的一部分(編譯是以C文件爲單位的,如果不在任何C文件中包含此頭文件的話,這段代碼就形同虛設),你可以在C文件中進行函數聲明,變量聲明,結構體聲明,這也不成問題!!!那爲何一定要分成頭文件與C文件呢?又爲何一般都在頭件中進行函數,變量聲明,宏聲明,結構體聲明呢?而在C文件中去進行變量定義,函數實現呢??原因如下: