問題
在進行C語言文件移植時,遇到 “通常是每個.c文件對應一個.h文件”,之前了解過.h文件是頭文件,用來引用其他文件的,
但在codeblocks C語言項目中找不到相應的.h文件:
所以,.c和.h文件到底什么關系,又怎么對應?
答案
.h文件的由來
“在編譯器只認識.c(.cpp))文件,而不知道.h是何物的年代,那時的人們寫了很多的.c(.cpp)文件,漸漸地,人們發現在很多.c(.cpp)文件中的聲明語句就是相同的,但他們卻不得不一個字一個字地重復地將這些內容敲入每個.c(.cpp)文件。但更為恐怖的是,當其中一個聲明有變更時,就需要檢查所有的.c(.cpp)文件。
於是人們將重復的部分提取出來,放在一個新文件里,然后在需要的.c(.cpp)文件中敲入#include XXXX這樣的語句。這樣即使某個聲明發生了變更,也再不需要到處尋找與修改了。因為這個新文件,經常被放在.c(.cpp)文件的頭部,所以就給它起名叫做“頭文件”,擴展名是.h。
在我們語言的初學階段,往往我們的程序只有一個.c的文件或這很少的幾個,這時我們就很少遇到頭文件組織這個頭疼的問題,隨着我們程序的增加,代碼 量到了幾千行甚至幾萬行,文件數也越來越多。這時這些文件的組織就成了一個問題,其實說白了這些文件的組織問題從理論上來說是軟件工程中的模塊設計等等的問題。”
由上可以看出,.h文件最初就是用來給變量和函數提供一些全局性的聲明,這些聲明被其他.c文件共享,方便變量和聲明的修改,使得大型代碼邏輯更清晰更易於維護。因此.h文件中一般是聲明,很少有代碼的具體實現。
那么為什么在.h文件中實現函數也不會出錯呢?
【在.h文件中實現函數與在.c文件中實現函數有什么區別和聯系呢?】
要解決上述問題,首先必須弄清編譯器的工作原理。編譯器的最終目的是將程序員編寫的源代碼轉換成機器能夠識別運行的二進制機器碼。
大體上分,可以分為4個步驟:
1.頭文件的預編譯,預處理
編譯器在編譯源代碼時,會先編譯頭文件,保證每個頭文件只被編譯一次。
在預處理階段,編譯器將c文件中引用的頭文件中的內容全部寫到c文件中。
2.詞法和語法分析(查錯)
3.編譯(匯編代碼,.obj文件)
轉化為匯編碼,這種文件稱為目標文件。后綴為.obj。
4.鏈接(二進制機器碼,.exe文件)
將匯編代碼轉換為機器碼,生成可執行文件。
因此,在編譯過程中,.h文件中的所有內容會被寫到包含它的.c文件中,而所有的.c文件以一個共同的main函數作為可執行程序的入口。
在.h文件中編寫函數實現並不會出錯,相當於所有.h的內容最后都被寫到了main.c文件中。但是為了邏輯性、易於維護性以及一些其他目的,一般在.h文件中寫函數的聲明,在.c文件中編寫函數的實現。
總的來說:
C程序的入口是main()函數,當我們遇到一個比較大的程序,需要被每個功能模塊區分開始,就需要使用不同的.c和.h文件。這樣方便自己管理和使用c程序,.h是頭文件,一般存放函數的聲明、數組、和定義的變量,.c是源文件,是實現函數程序的功能。
如何使用.c和.h呢?
首先需要建立一個xx.h文件,這里面是函數的聲明和一些變量的定義,其次建立一個同名的xx.c文件,這里面是實現某個函數的功能例如(xiangcheng(int a,intb)),然后新建一個xx.c文件這里面是實現xiangcheng(int a,int b)的函數,當需要調用這個xiangcheng(int a,int b)的函數時只需要在函數的頭部加上xx.h頭文件即可,這樣就完成了不同文件函數之間的調用。