C標頭檔聲明和實現分開

來源:互聯網
上載者:User
類聲明放到.h檔案
實現放到cpp檔案

標頭檔(.h)主要包含函數的聲明、宏定義等源檔案(.cpp)是函數 的實現部分 是主體部分。

在C語言裡面,有時候為了方便(方便的同義字是偷懶),函數就直接在標頭檔裡面實現了。那麼這樣子有什麼問題呢?
下面舉個例子,這個例子只有3個檔案


#ifndef FUN_H#define FUN_Hvoid base(){};void fun();#endif#include "fun.h"void fun(){base();}#include "fun.h"int main(){fun();return 0;}

好,然後gcc一下
gcc -c main.c (通過)
gcc -c fun.c (通過)
gcc -o main main.o fun.o (連結錯誤)
出現錯誤...“base()函數重定義!”

為什麼重定義呢?因為#include是預先處理部分,在編譯之前由預先處理程式在這個部分複製標頭檔的內容過來。所以在編譯時間候,main.o和fun.o檔案都有base()函數的定義。那麼連結程式就不知道連結那個定義好了(二義性啊)
如何解決呢,為了實現“聲明和實現分開”這個目標最好就是把這個base函數的函數體移到源檔案裡面。如果由於某種原因真的要放在標頭檔中...也可以。
用static聲明就可以了,靜態函數的範圍是檔案,而不是全域。比如,
上面的例子將標頭檔裡面的void base(){}改成static voidbase(){},那就OK。這個static在c語言中的用法可以google下,上面的資料好多很詳細滴。

順便說說標頭檔的循環相依性的問題。
比如有三個標頭檔a.h b.h c.h,a.h裡面有#include "b.h",b.h裡面有#include "c.h",c.h裡面有#include "a.h",那就會造成檔案的循環相依性,後果是什麼呢?
比如有個檔案a.c,上面有#include"a.h",那在a.c檔案編譯之前,預先處理程式就會不斷的把這三個標頭檔的內容複寫過來,超過了一定的數量,就會導致“標頭檔數太多”的編譯錯誤。

解決方案呢,當然就是常見的#ifndef...#define...#endif組合了。不過要把前兩個寫在標頭檔的開頭(一定是開頭),最後一個寫在最末尾。

這樣的話,第一次展開a.h b.h c.h的時候就已經定義了宏,到了c.h中的#include"a.h"時候,遇到了#ifndef,由於這個宏在上一次展開時已經定義了,所以這部分就跳過去了。也就是每個標頭檔最多隻在每個源檔案裡麵包含一次。
但是即使編譯連結沒有問題,循環相依性也會降低開發效率,為什嗎?因為檔案都在依賴,比如某一天,要改變a.h的一部分內容,然後所有依賴於a.hb.hc.h的檔案都得重新編譯...連結;所以現在的C++有“前向聲明”的技巧可以緩解這個問題。(緩解並不是解決。)而JAVA運用的import機制就很好的解決了這個問題,真正實現了“實現與聲明相分離”這個目標。

/*zyrandom.h*/#ifndef __ZYRANDOM__#define __ZYRANDOM__void Randomize();#endif/*zyrandom.c*/#include <stdlib.h>#include <time.h>#ifndef __ZYRANDOM__#include "zyrandom.h"#endifvoid Randomize(){     srand((int)time(0));}/*main.c*/#include <stdio.h>#include <stdlib.h>#include "zyrandom.h"int main(){    int a;    Randomize();    a=rand();    printf("%d\n",a);    system("pause");    return 0;}

把上面三個檔案放在一個工程之中
1.為什麼標頭檔"zyrandom.h"隻字未提它的源檔案"zyrandom.c",它也能找到裡面的函數的定義2.源檔案"zyrandom.c"裡面的這3行代碼有實際意義嗎?#ifndef __ZYRANDOM__#include "zyrandom.h"#endif3.使用條件編譯的目的之一就是避免重複定義,那麼問什麼"main.c"和"zyrandom.c"裡面重複包含了<stdlib.h>也能正確編譯呢? 回答:
1,zyrandom.h檔案聲明函數void Randomize();的時候,其實預設關鍵字是extern,代表這函數可能在別的檔案中定義。所以.h中是聲明,而.c中是定義,所以包括.h檔案的話,自然能找到函數的定義。2,我感覺意義不大(我的看法,也許不是太對,但要是我寫的話肯定不這麼寫,因為它要表達的意思很不好,給人誤解)3,它沒有重複包含,main只包含了zyrandom.h,並未包含zyrandom.c啊。不過我感覺畢竟是標準庫,重複包含了也不一定錯,這點你可以試一下啊,咱雖然盡量避免這種可能的錯誤,但可以試一下到底是怎麼回事,是會錯誤,還是沒問題,還是編譯器相關。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.