




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、c語言頭文件的作用最近在工作當(dāng)中遇到了一點小問題,關(guān)于c語言頭文件的應(yīng)用問題,主要還是關(guān)于全局變量的定義和聲明問題.學(xué)習(xí)c語言已經(jīng)有好幾年了,工作使用也近半年了,但是對于這部分的東西的確還沒有深入的思考過.概念上還是比較模糊的,只是之前的使用大多比較簡單,并沒有牽涉到太復(fù)雜的工程,所以定義和聲明還是比較簡單而明了了的.但是最近的大工程讓我在這方面吃到了一點點苦頭,雖然看了別人的代碼能夠很快的改正,但是這些改正背后的原因卻不知道.我想大多數(shù)喜歡c語言的程序員應(yīng)該是和我一樣的,總喜歡去追究程序問題背后的底層原因,而這也恰恰是我喜歡c語言的最根本的原因.今天看過janders老兄在csdn上的一篇文
2、章后,理解的確加深了很多,而且還學(xué)到一些以前不怎么知道的知識.現(xiàn)將文章轉(zhuǎn)載過來,并對文章當(dāng)中的一些拼寫錯誤做了簡單的糾正,同時對文字及布局做了少許修改.(如果想看原文的,請參考本文底部的鏈接.)c語言中的.h文件和我認識由來已久,其使用方法雖不十分復(fù)雜,但我卻是經(jīng)過了幾個月的“不懂”時期,幾年的“一知半解”時期才逐漸認識清楚他的本來面目。揪其原因,我的駑鈍和好學(xué)而不求甚解固然是原因之一,但另外還有其他原因。原因一:對于較小的項目,其作用不易被充分開發(fā),換句話說就是即使不知道他的詳細使用方法,項目照樣進行,程序在計算機上照樣跑。原因二:現(xiàn)在的各種c語言書籍都是只對c語言的語法進行詳細的不能再詳細
3、的說明,但對于整個程序的文件組織構(gòu)架卻只字不提,找了好幾本比較著名的c語言著作,卻沒有一個把.h文件的用法寫的比較透徹的。下面我就斗膽提筆,來按照我對.h的認識思路,向大家介紹一下。讓我們的思緒乘著時間機器回到大學(xué)一年級。c原來老師正在講臺上講著我們的第一個c語言程序: hello world!文件名 first.cmain() printf(“hello world!”); 例程-1看看上面的程序,沒有.h文件。是的,就是沒有,世界上的萬物都是經(jīng)歷從沒有到有的過程的,我們對.h的認識,我想也需要從這個步驟開始。這時確實不需要.h文件,因為這個程序太簡單了,根本就不需要。那么如何才能需要呢?讓
4、我們把這個程序變得稍微復(fù)雜些,請看下面這個,文件名 first.cprintstr() printf(“hello world!”);main()printstr(); 例程-2還是沒有, 那就讓我們把這個程序再稍微改動一下.文件名 first.cmain()printstr();printstr() printf(“hello world!”); 例程-3等等,不就是改變了個順序嘛, 但結(jié)果確是十分不同的. 讓我們編譯一下例程-2和例程-3,你會發(fā)現(xiàn)例程-3是編譯不過的.這時需要我們來認識一下另一個c語言中的概念:作用域. 我們在這里只講述與.h文件相關(guān)的頂層作用域, 頂層作用域就是從聲明點
5、延伸到源程序文本結(jié)束, 就printstr()這個函數(shù)來說,他沒有單獨的聲明,只有定義,那么就從他定義的行開始,到first.c文件結(jié)束, 也就是說,在在例程-2的main()函數(shù)的引用點上,已經(jīng)是他的作用域. 例程-3的main()函數(shù)的引用點上,還不是他的作用域,所以會編譯出錯. 這種情況怎么辦呢? 有兩種方法 ,一個就是讓我們回到例程-2, 順序?qū)ξ覀儊碚f沒什么, 誰先誰后不一樣呢,只要能編譯通過,程序能運行, 就讓main()文件總是放到最后吧. 那就讓我們來看另一個例程,讓我們看看這個方法是不是在任何時候都會起作用.文件名 first.c play2() .play1();. pla
6、y1() .play2(); main()play1();例程-4也許大部分都會看出來了,這就是經(jīng)常用到的一種算法, 函數(shù)嵌套, 那么讓我們看看, play1和play2這兩個函數(shù)哪個放到前面呢? 這時就需要我們來使用第二種方法,使用聲明. 文件名 first.cplay1();play2();play2().play1();. play1() .play2(); main()play1();例程-4經(jīng)歷了我的半天的嘮叨, 加上四個例程的說明,我們終于開始了用量變引起的質(zhì)變, 這篇文章的主題.h文件快要出現(xiàn)了。一個大型的軟件項目,可能有幾千個,上萬個play, 而不只是play1,play2這
7、么簡單, 這樣就可能有n個類似 play1(); play2(); 這樣的聲明, 這個時候就需要我們想辦法把這樣的play1(); play2(); 也另行管理, 而不是把他放在.c文件中, 于是.h文件出現(xiàn)了.文件名 first.hplay1();play2();文件名 first.c#include “first.h”play2().play1();. play1(); . play2(); main()play1();例程-4各位有可能會說,這位janders大蝦也太羅嗦了,上面這些我也知道, 你還講了這么半天, 請原諒, 如果說上面的內(nèi)容80%的人都知道的話,那么我保證,下面的內(nèi)容,8
8、0%的人都不完全知道. 而且這也是我講述一件事的一貫作風(fēng),我總是想把一個東西說明白,讓那些剛剛接觸c的人也一樣明白.上面是.h文件的最基本的功能,那么.h文件還有什么別的功能呢? 讓我來描述一下我手頭的一個項目吧.這個項目已經(jīng)做了有10年以上了,具體多少年我們部門的人誰都說不太準確,況且時間并不是最主要的,不再詳查了。是一個通訊設(shè)備的前臺軟件, 源文件大小共 51.6m, 大小共1601個文件, 編譯后大約10m, 其龐大可想而知,在這里充斥著錯綜復(fù)雜的調(diào)用關(guān)系,如在second.c中還有一個函數(shù)需要調(diào)用first.c文件中的play1函數(shù), 如何實現(xiàn)呢? sencond.h 文件play1(
9、);sencond.c文件*().play();.例程-5在second.h文件內(nèi)聲明play1函數(shù),怎么能調(diào)用到first.c文件中的哪個play1函數(shù)中呢? 是不是搞錯了,沒有搞錯, 這里涉及到c語言的另一個特性:存儲類說明符.c語言的存儲類說明符有以下幾個, 我來列表說明一下 說明符用 法auto只在塊內(nèi)變量聲明中被允許, 表示變量具有本地生存期.extern出現(xiàn)在頂層或塊的外部變量函數(shù)與變量聲明中,表示聲明的對象具有靜態(tài)生存期, 連接程序知道其名字.static可以放在函數(shù)與變量聲明中,在函數(shù)定義時,只用于指定函數(shù)名,而不將函數(shù)導(dǎo)出到鏈接程序,在函數(shù)聲明中,表示其后邊會有定義聲明的函數(shù)
10、,存儲類型static.在數(shù)據(jù)聲明中,總是表示定義的聲明不導(dǎo)出到連接程序.無疑, 在例程-5中的second.h和first.h中,需要我們用extern標志符來修飾play1函數(shù)的聲明,這樣,play1()函數(shù)就可以被導(dǎo)出到連接程序, 也就是實現(xiàn)了無論在first.c文件中調(diào)用,還是在second.c文件中調(diào)用,連接程序都會很聰明的按照我們的意愿,把他連接到first.c文件中的play1函數(shù)的定義上去, 而不必我們在second.c文件中也要再寫一個一樣的play1函數(shù).但隨之有一個小問題, 在例程-5中,我們并沒有用extern標志符來修飾play1啊, 這里涉及到另一個問題, c語言中
11、有默認的存儲類標志符. c99中規(guī)定, 所有頂層的默認存儲類標志符都是extern . 原來如此啊,哈哈.回想一下例程-4, 也是好險, 我們在無知的情況下, 竟然也誤打誤撞,用到了extern修飾符, 否則在first.h中聲明的play1函數(shù)如果不被連接程序?qū)С?那么我們在在play2()中調(diào)用他時, 是找不到其實際定義位置的 .那么我們?nèi)绾蝸韰^(qū)分哪個頭文件中的聲明在其對應(yīng)的.c文件中有定義,而哪個又沒有呢?這也許不是必須的,因為無論在哪個文件中定義,聰明的連接程序都會義無返顧的幫我們找到,并導(dǎo)出到連接程序, 但我覺得他確實必要的. 因為我們需要知道這個函數(shù)的具體內(nèi)容是什么,有什么功能,
12、有了新需求后我也許要修改他,我需要在短時間內(nèi)能找到這個函數(shù)的定義, 那么我來介紹一下在c語言中一個人為的規(guī)范:在.h文件中聲明的函數(shù),如果在其對應(yīng)的.c文件中有定義,那么我們在聲明這個函數(shù)時,不使用extern修飾符, 如果反之,則必須顯示使用extern修飾符.這樣,在c語言的.h文件中,我們會看到兩種類型的函數(shù)聲明. 帶extern的,還不帶extern的, 簡單明了,一個是引用外部函數(shù),一個是自己生命并定義的函數(shù).最終如下:sencond.h 文件extern play1();上面洋洋灑灑寫了那么多都是針對函數(shù)的,而實際上.h文件卻不是為函數(shù)所御用的. 打開我們項目的一個.h文件我們發(fā)現(xiàn)
13、除了函數(shù)外,還有其他的東西, 那就是全局變量.在大型項目中,對全局變量的使用不可避免, 比如,在first.c中需要使用一個全局變量g_test, 那么我們可以在first.h中,定義 tpye g_test. 與對函數(shù)的使用類似, 在second.c中我們的開發(fā)人員發(fā)現(xiàn)他也需要使用這個全局變量, 而且要與first.c中一樣的那個, 如何處理? 對,我們可以仿照函數(shù)中的處理方法, 在second.h中再次聲明tpye g_test, 根據(jù)extern的用法,以及c語言中默認的存儲類型, 在兩個頭文件中聲明的tpye g_test,其實其存儲類型都是extern, 也就是說不必我們操心, 連接
14、程序會幫助我們處理一切. 但我們又如何區(qū)分全局變量哪個是定義聲明,哪個是引用聲明呢?這個比函數(shù)要復(fù)雜一些, 一般在c語言中有如下幾種模型來區(qū)分:1、初始化語句模型頂層聲明中,存在初始化語句是,表示這個聲明是定義聲明,其他聲明是引用聲明。c語言的所有文件之中,只能有一個定義聲明。按照這個模型,我們可以在first.h中定義如下tpye g_test=1;那么就確定在first中的是定義聲明,在其他的所有聲明都是引用聲明。2、省略存儲類型說明在這個模型中,所有引用聲明要顯示的包括存儲類extern,而每個外部變量的唯一定義聲明中省略存儲類說明符。這個與我們對函數(shù)的處理方法類似,不再舉例說明。 這里
15、還有一個需要說明,本來與本文并不十分相關(guān),但前一段有個朋友遇到此問題,相信很多人都會遇到,那就是數(shù)組全局變量。他遇到的問題如下:在聲明定義時,定義數(shù)組如下:int g_glob100;在另一個文件中引用聲明如下:int * g_glob;在vc中,是可以編譯通過的,這種情況大家都比較模糊并且需要注意,數(shù)組與指針類似,但并不等于說對數(shù)組的聲明起變量就是指針。上面所說的的程序在運行時發(fā)現(xiàn)了問題,在引用聲明的那個文件中,使用這個指針時總是提示內(nèi)存訪問錯誤,原來我們的連接程序并不把指針與數(shù)組等同,連接時,也不把他們當(dāng)做同一個定義,而是認為是不相關(guān)的兩個定義,當(dāng)然會出現(xiàn)錯誤。正確的使用方法是在引用聲明中
16、聲明如下:int g_glob100;并且最好再加上一個extern,更加明了。extern int g_glob100; 另外需要說明的是,在引用聲明中由于不需要涉及到內(nèi)存分配,可以簡化如下,這樣在需要對全局變量的長度進行修改時,不用把所有的引用聲明也全部修改了。extern int g_glob; c語言是現(xiàn)今為止在底層核心編程中,使用最廣泛的語言,以前是,以后也不會有太大改變,雖然現(xiàn)在java,.net等語言和工具對c有了一定沖擊,但我們看到在計算機最為核心的地方,其他語言是無論如何也代替不了的,而這個領(lǐng)域也正是我們對計算機癡迷的程序員所向往的。好了,看完文章,對與c語言頭文件的作用應(yīng)該
17、有了跟多的理解吧,如果這些你原本都知道了,那么僅當(dāng)是溫習(xí)一下而已,如果原本不知道,那么恭喜你,現(xiàn)在又學(xué)到一些技巧和知識.對于全局變量的定義和聲明,其實還有另外一個解決的方法,聰明的你可能早已經(jīng)猜到了:),沒錯,就是用宏定義的技巧實現(xiàn).比如a.h文件當(dāng)中有: #ifdef aaaint i=0;#elseint i;#endif那么,在a.c文件當(dāng)中,有如下語句:.#define aaa#include a.h.而對于其他的任何包含a.h文件的頭文件或者.c源文件,只需要直接包含a.h就行了.#include a.h.這樣就可以達到在a.c文件當(dāng)中定義變量一次,而在其他的文件當(dāng)中聲明該變量的目的.當(dāng)然了,你完全可以根據(jù)自己的需要來決定在哪個需要包含a.h的文件當(dāng)中定義宏aaa,但是我要說的是在同一個工程的不同的需要包含a.h的文件當(dāng)中,你只能定義aaa一次,否則在連接這些目標文件時會出現(xiàn)重復(fù)定義的錯誤,即使你的單獨目標文件編譯沒有任何的問題.當(dāng)然,這里說的僅僅是對全局變量的聲明技巧,強烈的推介大家在頭文件中使用宏定義實現(xiàn)對整個頭文件的防止重復(fù)包含,當(dāng)然了,這
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度燒烤店轉(zhuǎn)讓合同含獨家配方及設(shè)備
- 2025年度藝術(shù)品抵押借款合同協(xié)議
- 二零二五年度汽車零部件制造廠房產(chǎn)權(quán)移交合同
- 二零二五年度瑜伽舞蹈工作室店鋪鋪面租賃協(xié)議
- 發(fā)言稿組織委員
- 2025年安徽貨運從業(yè)資格考試題目大全答案
- 老母親遺留房產(chǎn)轉(zhuǎn)讓合同
- 2014年飯店轉(zhuǎn)讓協(xié)議
- 高一新生會發(fā)言稿
- 2025年上海貨運從業(yè)資格證考試新規(guī)
- (2025春新教材)部編版七年級語文下冊全冊教案
- 2024年12月重慶大學(xué)醫(yī)院公開招聘醫(yī)生崗位2人(有編制)筆試歷年典型考題(歷年真題考點)解題思路附帶答案詳解
- 主題班會:新學(xué)期 新起點 新期待
- 2024 河北公務(wù)員考試(筆試、省直、A類、C類)4套真題及答案
- 統(tǒng)編版歷史 選擇性必修二第12課 《水陸交通的變遷》課件(共27張)
- 小學(xué)生雙擁活動國防教育
- 消防風(fēng)道風(fēng)管施工方案
- 2025年湖南省煙草專賣局系統(tǒng)招聘336人高頻重點提升(共500題)附帶答案詳解
- 交通安全勸導(dǎo)講座課件
- 和利時DCS系統(tǒng)課件
- 2.2 生態(tài)脆弱區(qū)的綜合治理 課件 【知識精研】高二地理人教版(2019)選擇性必修2
評論
0/150
提交評論