c語言中頭文件的-函數(shù)-全局變量-extern_第1頁
c語言中頭文件的-函數(shù)-全局變量-extern_第2頁
c語言中頭文件的-函數(shù)-全局變量-extern_第3頁
c語言中頭文件的-函數(shù)-全局變量-extern_第4頁
c語言中頭文件的-函數(shù)-全局變量-extern_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、頭文件中一般放一些重復(fù)使用的代碼,例如函數(shù)聲明,變量聲明,常數(shù)定義,宏的定義等等。當(dāng)使用include語句將頭文件引用時(shí),相當(dāng)于將頭文件中所有內(nèi)容,復(fù)制到include處。為了避免因?yàn)橹貜?fù)引用而導(dǎo)致的編譯錯(cuò)誤,頭文件常具有 #ifndef   LABEL#define   LABEL   /代碼部分#endif的格式。其中,LABEL為一個(gè)唯一的標(biāo)號(hào),命名規(guī)則跟變量的命名規(guī)則一樣。常根據(jù)它所在的頭文件名來命名,例如,如果頭文件的文件名叫做hardware.h,那么可以這樣使用:#ifndef   _HARDWARE

2、_H_ #define   _HARDWARE_H_ /代碼部分#endif這樣寫的意思就是,如果沒有定義_HARDWARE_H_,則定義_HARDWARE_H_,并編譯下面的代碼部分,直到遇到#endif。這樣,當(dāng)重復(fù)引用時(shí),由于_HARDWARE_H_已經(jīng)被定義,則下面的代碼部分就不會(huì)被編譯了,這樣就避免了重復(fù)定義。另外一個(gè)地方就是使用include時(shí),使用引號(hào)(“”)時(shí),首先搜索工程文件所在目錄,然后再搜索編譯器頭文件所在目錄。而使用尖括號(hào)(<>)時(shí),剛好是相反的搜索順序。  C語言頭文件的使用讓我們的思緒乘著時(shí)間機(jī)器回到大學(xué)一年級(jí)。C原來老師正

3、在講臺(tái)上講著我們的第一個(gè)C語言程序: Hello world!文件名 First.cmain()     printf(“Hello world!”);例程-1看看上面的程序,沒有.h文件。是的,就是沒有,世界上的萬物都是經(jīng)歷從沒有到有的過程的,我們對(duì).h的認(rèn)識(shí),我想也需要從這個(gè)步驟開始。這時(shí)確實(shí)不需要.h文件,因?yàn)檫@個(gè)程序太簡單了,根本就不需要。那么如何才能需要呢?讓我們把這個(gè)程序變得稍微復(fù)雜些,請(qǐng)看下面這個(gè),文件名 First.cprintStr()     printf(“Hello world!”);mai

4、n()printStr()     例程-2還是沒有, 那就讓我們把這個(gè)程序再稍微改動(dòng)一下.文件名 First.cmain()printStr()printStr()     printf(“Hello world!”);     例程-3等等,不就是改變了個(gè)順序嘛, 但結(jié)果確是十分不同的. 讓我們編譯一下例程-2和例程-3,你會(huì)發(fā)現(xiàn)例程-3是編譯不過的.這時(shí)需要我們來認(rèn)識(shí)一下另一個(gè)C語言中的概念:作用域.我們?cè)谶@里只講述與.h文件相關(guān)的頂層作用域, 頂層作用域就是從聲明點(diǎn)延

5、伸到源程序文本結(jié)束, 就printStr()這個(gè)函數(shù)來說,他沒有單獨(dú)的聲明,只有定義,那么就從他定義的行開始,到first.c文件結(jié)束, 也就是說,在在例程-2的main()函數(shù)的引用點(diǎn)上,已經(jīng)是他的作用域. 例程-3的main()函數(shù)的引用點(diǎn)上,還不是他的作用域,所以會(huì)編譯出錯(cuò). 這種情況怎么辦呢? 有兩種方法 ,一個(gè)就是讓我們回到例程-2, 順序?qū)ξ覀儊碚f沒什么, 誰先誰后不一樣呢,只要能編譯通過,程序能運(yùn)行, 就讓main()文件總是放到最后吧. 那就讓我們來看另一個(gè)例程,讓我們看看這個(gè)方法是不是在任何時(shí)候都會(huì)起作用.文件名 First.cplay2()play1();play1()&#

6、160;    play2();main()play1();例程-4也許大部分都會(huì)看出來了,這就是經(jīng)常用到的一種算法, 函數(shù)嵌套, 那么讓我們看看, play1和play2這兩個(gè)函數(shù)哪個(gè)放到前面呢?這時(shí)就需要我們來使用第二種方法,使用聲明.文件名 First.cplay1();play2();play2()play1();play1()     play2(););main()play1()例程-4一個(gè)大型的軟件項(xiàng)目,可能有幾千個(gè),上萬個(gè)play, 而不只是play1,play2這么簡單, 這樣就可能有N個(gè)類似 play1(

7、); play2(); 這樣的聲明, 這個(gè)時(shí)候就需要我們想辦法把這樣的play1(); play2(); 也另行管理, 而不是把他放在.c文件中, 于是.h文件出現(xiàn)了 。文件名 first.hplay1();play2();文件名 first.C#include “first.h”play2()play1();play1()     play2() ;main()play1() ;例程-4上面是.h文件的最基本的功能, 那么.h文件還有什么別的功能呢?如在 second.c 中還有一個(gè)函數(shù)需要調(diào)用 first.c 文件中的play1函數(shù), 如何實(shí)現(xiàn)呢?

8、Sencond.h 文件play1();sencond.c文件*()Play();例程-5在sencond.h文件內(nèi)聲明play1函數(shù),怎么能調(diào)用到first.c文件中的哪個(gè)play1函數(shù)中呢? 是不是搞錯(cuò)了,沒有搞錯(cuò), 這里涉及到c語言的另一個(gè)特性:存儲(chǔ)類說明符.C語言的存儲(chǔ)類說明符有以下幾個(gè), 我來列表說明一下說明符                用法Auto     只在塊內(nèi)變量聲

9、明中被允許, 表示變量具有本地生存期.Extern    出現(xiàn)在頂層或塊的外部變量函數(shù)與變量聲明中,表示聲明的對(duì)象Static    具有靜態(tài)生存期, 連接程序知道其名字.可以放在函數(shù)與變量聲明中. 在函數(shù)定義時(shí), 其只用于指定函數(shù)名,而不將函數(shù)導(dǎo)出到連接程序. 在函數(shù)聲明中,表示其后面會(huì)有定義聲明的函數(shù), 存儲(chǔ)類為static. 在數(shù)據(jù)聲明中, 總是表示定義的聲明不導(dǎo)出到連接程序.無疑, 在例程-5中的second.h和first.h中,需要我們用extern標(biāo)志符來修飾play1函數(shù)的聲明,這樣,play1()函數(shù)就可以

10、被導(dǎo)出到連接程序, 也就是實(shí)現(xiàn)了無論在first.c文件中調(diào)用,還是在second.c文件中調(diào)用,連接程序都會(huì)很聰明的按照我們的意愿,把他連接到first.c文件中 的 play1 函數(shù)的定義上去, 而不必我們?cè)趕econd.c文件中也要再寫一個(gè)一樣的play1函數(shù) 。但隨之有一個(gè)小問題, 在例程-5中,我們并沒有用extern標(biāo)志符來修飾play1啊, 這里涉及到另一個(gè)問題, C語言中有默認(rèn)的存儲(chǔ)類標(biāo)志符. C99中規(guī)定, 所有頂層的默認(rèn)存儲(chǔ)類標(biāo)志符都是extern . 原來如此啊, 哈哈. 回想一下例程-4, 也是好險(xiǎn), 我們?cè)跓o知的情況下, 竟然也誤打誤撞,用到了extern修飾符, 否

11、則在first.h中聲明的play1函數(shù)如果不被連接程序?qū)С?那么我我們?cè)趐lay2()中調(diào)用他時(shí), 是找不到其實(shí)際定義位置的。那么我們?nèi)绾蝸韰^(qū)分哪個(gè)頭文件中的聲明在其對(duì)應(yīng)的.c文件中有定義,而哪個(gè)又沒有呢? 這也許不是必須的,因?yàn)闊o論在哪個(gè)文件中定義,聰明的連接程序都會(huì)義無返顧的幫我們找到,并導(dǎo)出到連接程序, 但我覺得他確實(shí)必要的. 因?yàn)槲覀冃枰肋@個(gè)函數(shù)的具體內(nèi)容是什么,有什么功能, 有了新需求后我也許要修改他, 我需要在短時(shí)間內(nèi)能找到這個(gè)函數(shù)的定義, 那么我來介紹一下在C語言中一個(gè)人為的規(guī)范:在.h文件中聲明的函數(shù),如果在其對(duì)應(yīng)的.c文件中有定義,那么我們?cè)诼暶鬟@個(gè)函數(shù)時(shí),不使用ext

12、ern修飾符, 如果反之,則必須顯示使用 extern修飾符.這樣,在C語言的.h文件中,我們會(huì)看到兩種類型的函數(shù)聲明. 帶extern的,還不帶extern的, 簡單明了,一個(gè)是引用外部函數(shù),一個(gè)是自己生命并定義的函數(shù).最終如下:Sencond.h 文件Extern play1();上面都是針對(duì)函數(shù)的,而實(shí)際上.h文件卻不是為函數(shù)所御用的. 打開我們項(xiàng)目的一個(gè).h文件我們發(fā)現(xiàn)除了函數(shù)外,還有其他的東西, 那就是全局變量. 在大型項(xiàng)目中,對(duì)全局變量的使用不可避免, 比如,在 first.c 中需要使用一個(gè)全局變量G_test, 那么我們可以在first.h中,定義 TPYE G_test. 與

13、對(duì)函數(shù)的使用類似, 在second.c中我們的開發(fā)人員發(fā)現(xiàn)他同樣也需要使用這個(gè)全局變量, 而且要與first.c中一樣的那個(gè), 如何處理? 對(duì),我們可以仿照函數(shù)中的處理方法, 在second.h中再次聲明TPYE G_test, 根據(jù)extern的用法,以及c語言中默認(rèn)的存儲(chǔ)類型, 在兩個(gè)頭文件中聲明的TPYE G_test,其實(shí)其存儲(chǔ)類型都是extern, 也就是說不必我們操心, 連接程序會(huì)幫助我們處理一切. 但我們又如何區(qū)分全局變量哪個(gè)是定義聲明,哪個(gè)是引用聲明呢?這個(gè)比函數(shù)要復(fù)雜一些, 一般在C語言中有如下幾種模型來區(qū)分的:1、 初始化語句模型頂層聲明中,存在初始化語句是,表示這個(gè)聲明是

14、定義聲明,其他聲明是引用聲明。C語言的所有文件之中,只能有一個(gè)定義聲明。按照這個(gè)模型,我們可以在first.h中定義如下TPYE G_test=1;那么就確定在first中的是定義聲明,在其他的所有聲明都是引用聲明。2、 省略存儲(chǔ)類型說明在這個(gè)模型中,所有引用聲明要顯示的包括存儲(chǔ)類extern, 而每個(gè)外部變量的唯一定義聲明中省略存儲(chǔ)類說明符。這個(gè)與我們對(duì)函數(shù)的處理方法比較類似,不再舉例說明。  這里還有一個(gè)地方需要說明,那就是數(shù)組全局變量。在聲明定義時(shí),定義數(shù)組如下:int G_glob100;在另一個(gè)文件中引用聲明如下:int * G_glob;在vc中,是可以編譯通過

15、的, 這種情況大家都比較模糊并且需要注意,數(shù)組與指針類似,但并不等于說對(duì)數(shù)組的聲明起變量就是指針。上面所說的的程序在運(yùn)行時(shí)發(fā)現(xiàn)了問題,在引用聲明的那個(gè)文件中,使用這個(gè)指針時(shí)總是提示內(nèi)存訪問錯(cuò)誤,原來我們的連接程序并不把指針與數(shù)組等同,連接時(shí), 也不把他們當(dāng)做同一個(gè)定義,而是認(rèn)為是不相關(guān)的兩個(gè)定義,當(dāng)然會(huì)出現(xiàn)錯(cuò)誤。正確的使用方法是在引用聲明中聲明如下:int G_glob10;并且最好再加上一個(gè)extern,更加明了。extern int G_glob10;  另外需要說明的是,在引用聲明中由于不需要涉及到內(nèi)存分配,可以簡化如下,這樣在需要對(duì)全局變量的長度進(jìn)行修改時(shí),不用把所有的引用聲

16、明也全部修改了。extern int G_glob;當(dāng)?shù)谝粋€(gè)頭文件用到*.h時(shí)相當(dāng)于定義了全局變量,并初始化了,第二個(gè)c文件再用*.h時(shí)應(yīng)該用 extern 寄存器了,按他一試,還真行啊!但是我不清楚,為何不能再在其他c文件中包含*.h。一般文件聲明、定義、調(diào)用的格式如下:應(yīng)用場(chǎng)景介紹:a.C 文件  、a.H文件  是兩個(gè)相關(guān)文件 ,b.c文件調(diào)用a.c文件中的定義的函數(shù)void a_function1(void);一般文件書寫格式:/*a.H文件 */void  a_fuction1(void);  

17、/ 聲明該函數(shù)/*a.C 文件 */#include"a.h"      void  a_fuction1(void)  / 定義該函數(shù)的具體實(shí)現(xiàn)             unsigned char aaa;              aaa=11;/*b.C 文件 */extern &#

18、160;void  a_fuction1(void);   / 告訴編譯器該函數(shù)在別處已經(jīng)聲明并且定義了,無需為其重新分配地址空間/=以下是準(zhǔn)備推薦一種c文件、h文件的寫法/*aa.H文件 */#ifdef   aa_h     #define  EXT              / -定義EXT 為空#else     #define&

19、#160; EXT   extern  /- 定義EXT 為extern ,后面的劇情大家大概猜到了吧#endifEXT  void  aa_fuction1(void);  / 聲明該函數(shù)/*aa.C 文件 */#define  aa_h            /此處有的定義雖為空,但是還是定義了-很重要的定義#include"aa.h"  &#

20、160;   void  aa_fuction1(void)  / 定義該函數(shù)的具體實(shí)現(xiàn)             unsigned char aaa;              aaa=11;/*bb.C 文件 */#include"aa.h"      / 直接包含頭文件即可實(shí)現(xiàn)調(diào)用,不

21、用逐個(gè)書寫extern +函數(shù)/全局變量的形式,比較簡潔以上是我在網(wǎng)站上搜集整理的,寫的很好,如果上面的那些你看懂了,下面就綜合一下:/*aa.H文件 */#ifndef   _aa_H#define   _aa_H#ifdef   aa_h     #define  EXT              / -定義EXT 為空#else     #define  EXT   extern  /- 定義EXT 為extern #e

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論