.c和.h的聯繫

  .c文件就是C語言系列的源文件,而H文件則是C語言的頭文件,即C系列中存放函數和全局變量的文件,由於C中的函數是被封裝起來的,即沒法看到其代碼。html

  子程序不要定義在*.h中。函數定義要放在*.c中,而*.h只作聲明.不然多引用幾回,就會發生函數重複定義的錯誤。*.h只作聲明,編譯後不產生代碼。這樣作目的是爲了實現軟件的模塊化,使軟件結構清晰,並且也便於別人使用你寫的程序。數組

 

  純粹用 C 語言語法的角度,你固然能夠在*.h 中聽任何東西,由於 #include 徹底等價於把*.h 文件 Ctrl-C Ctrl-V 到*.c 中,*.h 中應該都是一些宏定義和變量、函數聲明,告訴別人你的程序「能幹什麼、該怎麼用」。*.c 中是全部變量和函數的定義,告訴計算機你的程序「該怎麼實現」。固然,若是一個*.h 被多個*.c 包含,並且*.h 中有對象(變量或函數)的定義,就會發生重複定義的錯誤了,聲明能夠無窮屢次,定義只能一次ide

  通常來講,一個C文件應該是一個模塊,若是你的程序僅僅有一個模塊(僅僅一個C文件),就能夠不用創建H文件了。不然你的模塊確定不是獨立的,你的模塊裏面的實現要被別的模塊調用。這個時候你最好生成一個頭文件(H文件),在頭文件裏面能夠聲明你的那些函數是公共的。當別的模塊包含你的頭文件後,就可使用你的公共聲明瞭。模塊化

  一個C對應一個H,這樣管理起來方便,好比你有一個"my.c",那麼就再添加一個"my.h":函數

1 #ifndef _MY_H
2 #define _MY_H
3     externvoidmy(void);
4 #endif
View Code

 

  其實在H文件裏寫函數也無所謂,只是不符合習慣而已。只要按照以上的格式寫,一個H文件添加多少次都無所謂,呵~spa

  Come from: http://topic.csdn.net/t/20060429/15/4723725.html .net

  簡單的說,其實要理解C文件與H文件有什麼不一樣之處,首先須要弄明白編譯器的工做過程,通常說來編譯器會作如下幾個過程: 代碼規範

     1.預處理階段 code

          2.詞法與語法分析階段 htm

          3.編譯階段,首先編譯成純彙編語句,再將之彙編成跟CPU相關的二進制碼,生成各個目標文件 

               4.鏈接階段,將各個目標文件中的各段代碼進行絕對地址定位,生成跟特定平臺相關的可執行文件,固然,最後還能夠用objcopy生成純二進制碼,也就是去掉了文件格式信息。

編譯器在編譯時是以C文件爲單位進行的,也就是說若是你的項目中一個C文件都沒有,那麼你的項目將沒法編譯,鏈接器是以目標文件爲單位,它將一個或多個目標文件進行函數與變量的重定位,生成最終的可執行文件,在PC上的程序開發,通常都有一個main函數,這是各個編譯器的約定,固然,你若是本身寫鏈接器腳本的話,能夠不用main函數做爲程序入口!!! 

 有了這些基礎知識,再言歸正傳,爲了生成一個最終的可執行文件,就須要一些目標文件,也就是須要C文件,而這些C文件中又須要一個main函數做爲可執行程序的入口,那麼咱們就從一個C文件入手,假定這個C文件內容以下: 

 

#include<stdio.h>
#include"mytest.h"

int main(int argc,char**argv)
{
    test =25;
    printf("test.................%d\n",test);
}

 

 

mytest.h文件的內容:

int test;

  

 如今以這個例子來說解編譯器的工做: 
        1.預處理階段:編譯器以C文件做爲一個單元,首先讀這個C文件,發現第一句與第二句是包含一個頭文件,就會在全部搜索路徑中尋找這兩個文件,找到以後,就會將相應頭文件中再去處理宏,變量,函數聲明,嵌套的頭文件包含等,檢測依賴關係,進行宏替換,看是否有重複定義與聲明的狀況發生,最後將那些文件中全部的東東所有掃描進這個當前的C文件中,造成一箇中間「C文件」。 
 
        2.編譯階段,在上一步中至關於將那個頭文件中的test變量掃描進了一箇中間C文件,那麼test變量就變成了這個文件中的一個全局變量,此時就將全部這個中間C文件的全部變量,函數分配空間,將各個函數編譯成二進制碼,按照特定目標文件格式生成目標文件,在這種格式的目標文件中進行各個全局變量,函數的符號描述,將這些二進制碼按照必定的標準組織成一個目標文件 。
 
       3.鏈接階段,將上一步成生的各個目標文件,根據一些參數,鏈接生成最終的可執行文件,主要的工做就是重定位各個目標文件的函數,變量等,至關於將各目標文件中的二進制碼按必定的規範合到一個文件中 。
       再回到C文件與頭文件各寫什麼內容的話題上: 
  1.若是在頭文件中實現一個函數體,那麼若是在多個C文件中引用它,並且又同時編譯多個C文件,將其生成的目標文件鏈接成一個可執行文件,在每一個引用此頭文件的C文件所生成的目標文件中,都有一份這個函數的代碼,若是這段函數又沒有定義成局部函數,那麼在鏈接時,就會發現多個相同的函數,就會報錯 。
  2.若是在頭文件中定義全局變量,而且將此全局變量賦初值,那麼在多個引用此頭文件的C文件中一樣存在相同變量名的拷貝,關鍵是此變量被賦了初值,因此編譯器就會將此變量放入DATA段,最終在鏈接階段,會在DATA段中存在多個相同的變量,它沒法將這些變量統一成一個變量,也就是僅爲此變量分配一個空間,而不是多份空間,假定這個變量在頭文件沒有賦初值,編譯器就會將之放入BSS段,鏈接器會對BSS段的多個同名變量僅分配一個存儲空間 。
  3.若是在C文件中聲明宏,結構體,函數等,那麼我要在另外一個C文件中引用相應的宏,結構體,就必須再作一次重複的工做,若是我改了一個C文件中的一個聲明,那麼又忘了改其它C文件中的聲明,這不就出了大問題了,程序的邏輯就變成了你不可想象的了,若是把這些公共的東東放在一個頭文件中,想用它的C文件就只須要引用一個就OK了!!!這樣豈不方便,要改某個聲明的時候,只須要動一下頭文件就好了。
  4.在頭文件中聲明結構體,函數等,當你須要將你的代碼封裝成一個庫,讓別人來用你的代碼,你又不想公佈源碼,那麼人家如何利用你的庫呢?也就是如何利用你的庫中的各個函數呢??一種方法是公佈源碼,別人想怎麼用就怎麼用,另外一種是提供頭文件,別人從頭文件中看你的函數原型,這樣人家才知道如何調用你寫的函數,就如同你調用printf函數同樣,裏面的參數是怎樣的??你是怎麼知道的??還不是看人家的頭文件中的相關聲明啊!!!固然這些東東都成了C標準,就算不看人家的頭文件,你同樣能夠知道怎麼使用 。 例子:
 
//a.h
void foo();
1 //a.c
2 #include"a.h"//個人問題出來了:這句話是要,仍是不要?
3 void foo()
4 {
5     return;
6 }

 

1 //main.c
2 #include"a.h"
3 int main(int argc,char*argv[])
4 {
5     foo();
6   return0;
7 }

 

針對上面的代碼,請回答三個問題: 
  1.a.c 中的 #include "a.h" 這句話是否是多餘的?爲何常常見 xx.c 裏面 include 對應的 xx.h? 
  2.若是 a.c 中不寫,那麼編譯器是否是會自動把 .h 文件裏面的東西跟同名的 .c 文件綁定在一塊兒? 
  3.第三個問題我給他改了一下:若是 a.c 中不寫include<>,那麼編譯器是否是會自動把 .h 文件裏面的東西跟同名的.c文件綁定在一塊兒?
 
下面是一位牛人的原話:
  從C編譯器角度看,.h和.c皆是浮雲,就是更名爲.txt、.doc也沒有大的分別。換句話說,就是.h和.c沒啥必然聯繫。.h中通常放的是同名.c文件中定義的變量、數組、函數的聲明,須要讓.c外部使用的聲明。這個聲明有啥用?只是讓須要用這些聲明的地方方便引用。由於 #include "xx.h" 這個宏其實際意思就是把當前這一行刪掉,把 xx.h 中的內容原封不動的插入在當前行的位置。因爲想寫這些函數聲明的地方很是多(每個調用 xx.c 中函數的地方,都要在使用前聲明一會兒),因此用 #include "xx.h" 這個宏就簡化了許多行代碼——讓預處理器本身替換好了。也就是說,xx.h 其實只是讓須要寫 xx.c 中函數聲明的地方調用(能夠少寫幾行字),至於 include 這個 .h 文件是誰,是 .h 仍是 .c,仍是與這個 .h 同名的 .c,都沒有任何須然關係。
       這樣你可能會說:啊?那我平時只想調用 xx.c 中的某個函數,卻 include了 xx.h 文件,豈不是宏替換後出現了不少無用的聲明?沒錯,確實引入了不少垃圾 ,可是它卻省了你很多筆墨,而且整個版面也看起來清爽的多。魚與熊掌不可得兼,就是這個道理。反正多些聲明(.h通常只用來放聲明,而放不定義,參見拙著「過馬路,左右看」)也無害處,又不會影響編譯,何樂而不爲呢?
翻回頭再看上面的3個問題,很好解答了吧?
 
 

它的解答以下:

1.不必定。這個例子中顯然是多餘的。可是若是.c中的函數也須要調用同個.c中的其它函數,那麼這個.c每每會include同名的.h,這樣就不須要爲聲明和調用順序而發愁了(C語言要求使用以前必須聲明,而include同名.h通常會放在.c的開頭)。有不少工程甚至把這種寫法約定爲代碼規範,以規範出清晰的代碼來。 

2.答:1中已經回答過了。 

3.答:不會。問這個問題的人絕對是概念不清,要不就是想混水摸魚。很是討厭的是中國的不少考試出的都是這種爛題,生怕別人有個清楚的概念了,絕對要把考生搞暈。

 

  一般狀況下a.c包含a.h,通常是由於a.h裏面定義了一些a.c裏面使用的一些宏,同時它裏面聲明瞭a.c裏面定義的,一些給a.c以外的.c文件用的函數,這樣的話其餘.c文件要使用a.c裏面的函數,就只須要#include "a.h"就好了。

相關文章
相關標籤/搜索