<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    jasmine214--love

    只有當(dāng)你的內(nèi)心總是充滿快樂(lè)、美好的愿望和寧?kù)o時(shí),你才能擁有強(qiáng)壯的體魄和明朗、快樂(lè)或者寧?kù)o的面容。
    posts - 731, comments - 60, trackbacks - 0, articles - 0

    C語(yǔ)言中的.h文件和我認(rèn)識(shí)由來(lái)已久,其使用方法雖不十分復(fù)雜,但我卻是經(jīng)過(guò)了幾個(gè)月的“不懂”時(shí)期,幾年的“一知半解”時(shí)期才逐漸認(rèn)識(shí)清楚他的本來(lái)面目。揪其原因,我的 駑鈍和好學(xué)而不求甚解固然是原因之一,但另外還有其他原因。原因一:對(duì)于較小的項(xiàng)目,其作用不易被充分開(kāi)發(fā),換句話說(shuō)就是即使不知道他的詳細(xì)使用方法,項(xiàng) 目照樣進(jìn)行,程序在計(jì)算機(jī)上照樣跑。原因二:現(xiàn)在的各種C語(yǔ)言書(shū)籍都是只對(duì)C語(yǔ)言的語(yǔ)法進(jìn)行詳細(xì)的不能再詳細(xì)的說(shuō)明,但對(duì)于整個(gè)程序的文件組織構(gòu)架卻只字不提,找了好幾本比較著名的C語(yǔ)言著作,卻沒(méi)有一個(gè)把.h文件的用法寫(xiě)的比較透徹的。下面我就斗膽提筆,來(lái)按照我對(duì).h的認(rèn)識(shí)思路,向大家介紹一下。
     
    讓我們的思緒乘著時(shí)間機(jī)器回到大學(xué)一年級(jí)。C原來(lái)老師正在講臺(tái)上講著我們的第一個(gè)C語(yǔ)言程序: Hello world!

     文件名 First.c
    main()
    {
         printf(“Hello world!”);
    }
         例程-1

    看看上面的程序,沒(méi)有.h文件。是的,就是沒(méi)有,世界上的萬(wàn)物都是經(jīng)歷從沒(méi)有到有的過(guò)程的,我們對(duì).h的認(rèn)識(shí),我想也需要從這個(gè)步驟開(kāi)始。這時(shí)確實(shí)不需要.h文件,因?yàn)檫@個(gè)程序太簡(jiǎn)單了,根本就不需要。那么如何才能需要呢?讓我們把這個(gè)程序變得稍微復(fù)雜些,請(qǐng)看下面這個(gè),

    文件名 First.c
     
     printStr()
    {
         printf(“Hello world!”);
    }
    main()
    {
    printStr();
    }
         例程-2

     
    還是沒(méi)有, 那就讓我們把這個(gè)程序再稍微改動(dòng)一下.
     
    文件名 First.c
    main()
    {
    printStr();
    }
     
     
     printStr()
    {
         printf(“Hello world!”);
    }
         例程-3
     
    等等,不就是改變了個(gè)順序嘛, 但結(jié)果確是十分不同的. 讓我們編譯一下例程-2和例程-3,你會(huì)發(fā)現(xiàn)例程-3是編譯不過(guò)的.這時(shí)需要我們來(lái)認(rèn)識(shí)一下另一個(gè)C語(yǔ)言中的概念:作用域.
    我們?cè)谶@里只講述與.h文件相關(guān)的頂層作用域, 頂層作用域就是從聲明點(diǎn)延伸到源程序文本結(jié)束, printStr()這個(gè)函數(shù)來(lái)說(shuō),他沒(méi)有單獨(dú)的聲明,只有定義,那么就從他定義的行開(kāi)始,first.c文件結(jié)束, 也就是說(shuō),在在例程-2main()函數(shù)的引用點(diǎn)上,已經(jīng)是他的作用域. 例程-3main()函數(shù)的引用點(diǎn)上,還不是他的作用域,所以會(huì)編譯出錯(cuò). 這種情況怎么辦呢? 有兩種方法 ,一個(gè)就是讓我們回到例程-2, 順序?qū)ξ覀儊?lái)說(shuō)沒(méi)什么, 誰(shuí)先誰(shuí)后不一樣呢,只要能編譯通過(guò),程序能運(yùn)行, 就讓main()文件總是放到最后吧. 那就讓我們來(lái)看另一個(gè)例程,讓我們看看這個(gè)方法是不是在任何時(shí)候都會(huì)起作用.
    文件名 First.c
       play2()
       {
     ……………….
     play1();
     ………………..
     
       }
       play1(){
        ……………..
     play2();      
        ……………………
       }
    main()
    {
    play1();
    }
    例程-4
     
    也許大部分都會(huì)看出來(lái)了,這就是經(jīng)常用到的一種算法, 函數(shù)嵌套, 那么讓我們看看, play1play2這兩個(gè)函數(shù)哪個(gè)放到前面呢?
     
    這時(shí)就需要我們來(lái)使用第二種方法,使用聲明.
    文件名 First.c
    play1();
    play2();
    play2()
    {
     ……………….
     play1();
     ………………..
        }
        play1()
        {
         …………………….
     play2();
     ……………………
        }
    main()
    {
    play1();
    }
    例程-4
     
    經(jīng)歷了我的半天的嘮叨, 加上四個(gè)例程的說(shuō)明,我們終于開(kāi)始了用量變引起的質(zhì)變, 這篇文章的主題.h文件快要出現(xiàn)了。
    一個(gè)大型的軟件項(xiàng)目,可能有幾千個(gè),上萬(wàn)個(gè)play, 而不只是play1,play2這么簡(jiǎn)單, 這樣就可能有N個(gè)類(lèi)似 play1(); play2(); 這樣的聲明, 這個(gè)時(shí)候就需要我們想辦法把這樣的play1(); play2(); 也另行管理, 而不是把他放在.c文件中, 于是.h文件出現(xiàn)了.
     
    文件名 First.h
    play1();
    play2();
    文件名 First.C
    #include “first.h”
    play2()
    {
     ……………….
     play1();
     ………………..
    }
        play1();
    {
    ……………………..
         play2();
      ……………………
    }
    main()
    {
    play1();
    }
    例程-4
     
    各位有可能會(huì)說(shuō),這位janders大蝦也太羅嗦了,上面這些我也知道, 你還講了這么半天, 請(qǐng)?jiān)?/span>, 如果說(shuō)上面的內(nèi)容80%的人都知道的話,那么我保證,下面的內(nèi)容,80%的人都不完全知道. 而且這也是我講述一件事的一貫作風(fēng),我總是想把一個(gè)東西說(shuō)明白,讓那些剛剛接觸C的人也一樣明白.
    上面是.h文件的最基本的功能那么.h文件還有什么別的功能呢? 讓我來(lái)描述一下我手頭的一個(gè)項(xiàng)目吧.
     
    這個(gè)項(xiàng)目已經(jīng)做了有10年以上了,具體多少年我們部門(mén)的人誰(shuí)都說(shuō)不太準(zhǔn)確,況且時(shí)間并不是最主要的,不再詳查了。是一個(gè)通訊設(shè)備的前臺(tái)軟件, 源文件大小共 51.6M, 大小共1601個(gè)文件, 編譯后大約10M, 其龐大可想而知在這里充斥著錯(cuò)綜復(fù)雜的調(diào)用關(guān)系,如在second.c中還有一個(gè)函數(shù)需要調(diào)用first.c文件中的play1函數(shù), 如何實(shí)現(xiàn)呢?
     
    Second.h 文件
     
    play1();
     
    second.c文件
     
    ***()
    {
    …………….
    Play();
    ……………….
    }
    例程-5
     
    second.h文件內(nèi)聲明play1函數(shù),怎么能調(diào)用到first.c文件中的哪個(gè)play1函數(shù)中呢? 是不是搞錯(cuò)了,沒(méi)有搞錯(cuò), 這里涉及到c語(yǔ)言的另一個(gè)特性:存儲(chǔ)類(lèi)說(shuō)明符.
    C語(yǔ)言的存儲(chǔ)類(lèi)說(shuō)明符有以下幾個(gè), 我來(lái)列表說(shuō)明一下

      

     說(shuō)明符  用    法
     Auto  只在塊內(nèi)變量聲明中被允許, 表示變量具有本地生存期.
     Extern  出現(xiàn)在頂層或塊的外部變量函數(shù)與變量聲明中,表示聲明的對(duì)象具有靜態(tài)生存期, 連接程序知道其名字.
     Static  可以放在函數(shù)與變量聲明中,在函數(shù)定義時(shí),只用于指定函數(shù)名,而不將函數(shù)導(dǎo)出到鏈接程序,在函數(shù)聲明中,表示其后邊會(huì)有定義聲明的函數(shù),存儲(chǔ)類(lèi)型static.在數(shù)據(jù)聲明中,總是表示定義的聲明不導(dǎo)出到連接程序.
     

    無(wú)疑, 在例程-5中的second.hfirst.h,需要我們用extern標(biāo)志符來(lái)修飾play1函數(shù)的聲明,這樣,play1()函數(shù)就可以被導(dǎo)出到連接程序, 也就是實(shí)現(xiàn)了無(wú)論在first.c文件中調(diào)用,還是在second.c文件中調(diào)用,連接程序都會(huì)很聰明的按照我們的意愿,把他連接到first.c文件中的play1函數(shù)的定義上去, 而不必我們?cè)?/span>second.c文件中也要再寫(xiě)一個(gè)一樣的play1函數(shù).
    但隨之有一個(gè)小問(wèn)題, 在例程-5,我們并沒(méi)有用extern標(biāo)志符來(lái)修飾play1, 這里涉及到另一個(gè)問(wèn)題, C語(yǔ)言中有默認(rèn)的存儲(chǔ)類(lèi)標(biāo)志符. C99中規(guī)定, 所有頂層的默認(rèn)存儲(chǔ)類(lèi)標(biāo)志符都是extern . 原來(lái)如此啊哈哈回想一下例程-4, 也是好險(xiǎn), 我們?cè)跓o(wú)知的情況下, 竟然也誤打誤撞,用到了extern修飾符, 否則在first.h中聲明的play1函數(shù)如果不被連接程序?qū)С?/span>,那么我們?cè)谠?/span>play2()中調(diào)用他時(shí), 是找不到其實(shí)際定義位置的 .
     
    那么我們?nèi)绾蝸?lái)區(qū)分哪個(gè)頭文件中的聲明在其對(duì)應(yīng)的.c文件中有定義,而哪個(gè)又沒(méi)有呢?這也許不是必須的,因?yàn)闊o(wú)論在哪個(gè)文件中定義,聰明的連接程序都會(huì)義無(wú)返顧的幫我們找到,并導(dǎo)出到連接程序, 但我覺(jué)得他確實(shí)必要的. 因?yàn)槲覀冃枰肋@個(gè)函數(shù)的具體內(nèi)容是什么,有什么功能, 有了新需求后我也許要修改他,我需要在短時(shí)間內(nèi)能找到這個(gè)函數(shù)的定義, 那么我來(lái)介紹一下在C語(yǔ)言中一個(gè)人為的規(guī)范:
     
    .h文件中聲明的函數(shù),如果在其對(duì)應(yīng)的.c文件中有定義,那么我們?cè)诼暶鬟@個(gè)函數(shù)時(shí),不使用extern修飾符, 如果反之,則必須顯示使用extern修飾符.
     
    這樣,C語(yǔ)言的.h文件中,我們會(huì)看到兩種類(lèi)型的函數(shù)聲明. extern,還不帶extern, 簡(jiǎn)單明了,一個(gè)是引用外部函數(shù),一個(gè)是自己生命并定義的函數(shù).
    最終如下:
    Second.h 文件
     
    Extern play1();
     
     
    上面洋洋灑灑寫(xiě)了那么多都是針對(duì)函數(shù)的,而實(shí)際上.h文件卻不是為函數(shù)所御用的. 打開(kāi)我們項(xiàng)目的一個(gè).h文件我們發(fā)現(xiàn)除了函數(shù)外,還有其他的東西, 那就是全局變量
     
    在大型項(xiàng)目中,對(duì)全局變量的使用不可避免, 比如,first.c中需要使用一個(gè)全局變量G_test, 那么我們可以在first.h,定義 TPYE G_test. 與對(duì)函數(shù)的使用類(lèi)似, second.c中我們的開(kāi)發(fā)人員發(fā)現(xiàn)他也需要使用這個(gè)全局變量, 而且要與first.c中一樣的那個(gè), 如何處理? 對(duì),我們可以仿照函數(shù)中的處理方法, second.h中再次聲明TPYE G_test, 根據(jù)extern的用法,以及c語(yǔ)言中默認(rèn)的存儲(chǔ)類(lèi)型, 在兩個(gè)頭文件中聲明的TPYE G_test,其實(shí)其存儲(chǔ)類(lèi)型都是extern, 也就是說(shuō)不必我們操心, 連接程序會(huì)幫助我們處理一切. 但我們又如何區(qū)分全局變量哪個(gè)是定義聲明,哪個(gè)是引用聲明呢?這個(gè)比函數(shù)要復(fù)雜一些, 一般在C語(yǔ)言中有如下幾種模型來(lái)區(qū)分:
     
    1初始化語(yǔ)句模型
    頂層聲明中,存在初始化語(yǔ)句是,表示這個(gè)聲明是定義聲明,其他聲明是引用聲明。C語(yǔ)言的所有文件之中,只能有一個(gè)定義聲明。
    按照這個(gè)模型,我們可以在first.h中定義如下TPYE G_test=1;那么就確定在first中的是定義聲明,在其他的所有聲明都是引用聲明。
    2省略存儲(chǔ)類(lèi)型說(shuō)明
    在這個(gè)模型中,所有引用聲明要顯示的包括存儲(chǔ)類(lèi)extern而每個(gè)外部變量的唯一定義聲明中省略存儲(chǔ)類(lèi)說(shuō)明符。
    這個(gè)與我們對(duì)函數(shù)的處理方法類(lèi)似,不再舉例說(shuō)明。
     
        這里還有一個(gè)需要說(shuō)明,本來(lái)與本文并不十分相關(guān),但前一段有個(gè)朋友遇到此問(wèn)題,相信很多人都會(huì)遇到,那就是數(shù)組全局變量。
     
    他遇到的問(wèn)題如下:
    在聲明定義時(shí),定義數(shù)組如下:
    int G_glob[100];
     
    在另一個(gè)文件中引用聲明如下:
    int * G_glob;
     
    vc中,是可以編譯通過(guò)的,這種情況大家都比較模糊并且需要注意,數(shù)組與指針類(lèi)似,但并不等于說(shuō)對(duì)數(shù)組的聲明起變量就是指針。上面所說(shuō)的的程序在運(yùn)行時(shí)發(fā)現(xiàn)了問(wèn)題,在引用聲明的那個(gè)文件中,使用這個(gè)指針時(shí)總是提示內(nèi)存訪問(wèn)錯(cuò)誤,原來(lái)我們的連接程序并不把指針與數(shù)組等同,連接時(shí),也不把他們當(dāng)做同一個(gè)定義,而是認(rèn)為是不相關(guān)的兩個(gè)定義,當(dāng)然會(huì)出現(xiàn)錯(cuò)誤。正確的使用方法是在引用聲明中聲明如下:
     
    int G_glob[100];
     
    并且最好再加上一個(gè)extern,更加明了。
     
    extern int G_glob[100];
     
        另外需要說(shuō)明的是,在引用聲明中由于不需要涉及到內(nèi)存分配,可以簡(jiǎn)化如下,這樣在需要對(duì)全局變量的長(zhǎng)度進(jìn)行修改時(shí),不用把所有的引用聲明也全部修改了。
     
    extern int G_glob[];
     
        C語(yǔ)言是現(xiàn)今為止在底層核心編程中,使用最廣泛的語(yǔ)言,以前是,以后也不會(huì)有太大改變,雖然現(xiàn)在java,.net等語(yǔ)言和工具對(duì)c有了一定沖擊,但我們看到在計(jì)算機(jī)最為核心的地方,其他語(yǔ)言是無(wú)論如何也代替不了的,而這個(gè)領(lǐng)域也正是我們對(duì)計(jì)算機(jī)癡迷的程序員所向往的。



    好了,看完文章,對(duì)與C語(yǔ)言頭文件的作用應(yīng)該有了跟多的理解吧,如果這些你原本都知道了,那么僅當(dāng)是溫習(xí)一下而已,如果原本不知道,那么恭喜你,現(xiàn)在又學(xué)到一些技巧和知識(shí).

    對(duì)于全局變量的定義和聲明,其實(shí)還有另外一個(gè)解決的方法,聰明的你可能早已經(jīng)猜到了:),沒(méi)錯(cuò),就是用宏定義的技巧實(shí)現(xiàn).比如a.h文件當(dāng)中有:
    #ifdef AAA
     int i=0;
    #else
     int i;
    #endif
    那么,在a.c文件當(dāng)中,有如下語(yǔ)句:
    ......
    #define AAA
    #include "a.h"

    ......
    而對(duì)于其他的任何包含a.h文件的頭文件或者.c源文件,只需要直接包含a.h就行了
    ......
    #include "a.h"

    ......
    這樣就可以達(dá)到在a.c文件當(dāng)中定義變量一次,而在其他的文件當(dāng)中聲明該變量的目的.

    當(dāng)然了,你完全可以根據(jù)自己的需要來(lái)決定在哪個(gè)需要包含a.h的文件當(dāng)中定義宏AAA,但是我要說(shuō)的是
    在同一個(gè)工程的不同的需要包含a.h的文件當(dāng)中,你只能定義AAA一次,否則在連接這些目標(biāo)文件時(shí)會(huì)出現(xiàn)
    重復(fù)定義的錯(cuò)誤,即使你的單獨(dú)目標(biāo)文件編譯沒(méi)有任何的問(wèn)題.

    當(dāng)然,這里說(shuō)的僅僅是對(duì)全局變量的聲明技巧,強(qiáng)烈的推介大家在頭文件中使用宏定義實(shí)現(xiàn)對(duì)整個(gè)頭文件的防止重復(fù)包含,當(dāng)然了,這個(gè)技巧大多數(shù)的c語(yǔ)言程序員都懂.
    #ifndef XXX
    #define XXX

    #endif

    這樣做會(huì)讓你的程序更加穩(wěn)健,很大程度上減少了不必要的麻煩...

    最后給出一點(diǎn)點(diǎn)全局變量使用需要注意的問(wèn)題,這也僅僅是個(gè)建議,或者說(shuō)一種編程習(xí)慣 ;)
    1) 所有全局變量全部以g_開(kāi)頭,并且盡可能聲明成static類(lèi)型.
    2) 盡量杜絕跨文件訪問(wèn)全局變量.如果的確需要在多個(gè)文件內(nèi)訪問(wèn)同一變量,應(yīng)該由該變量定義所在文件內(nèi)提供GET/PUT函數(shù)實(shí)現(xiàn).
    3) 全局變量必須要有一個(gè)初始值,全局變量盡量放在一個(gè)專(zhuān)門(mén)的函數(shù)內(nèi)初始化.
    4) 如調(diào)用的函數(shù)少于三個(gè),請(qǐng)考慮改為局部變量實(shí)現(xiàn).

    如果文中有什么不對(duì)的地方,歡迎指正,相互學(xué)習(xí):)
    原文:http://blogold.chinaunix.net/u2/75758/showart_1715158.html

    Feedback

    # re: C語(yǔ)言中的.h文件的作用  回復(fù)  更多評(píng)論   

    2012-08-01 15:27 by 董璐
    2) 盡量杜絕跨文件訪問(wèn)全局變量.如果的確需要在多個(gè)文件內(nèi)訪問(wèn)同一變量,應(yīng)該由該變量定義所在文件內(nèi)提供GET/PUT函數(shù)實(shí)現(xiàn).


    上面這條可否給個(gè)示例?非常感謝:donglu918@163.com

    # re: C語(yǔ)言中的.h文件的作用  回復(fù)  更多評(píng)論   

    2013-10-22 15:15 by seeking
    例程-1 和 例程-2 無(wú)法通過(guò),printf函數(shù)屬于stdio.h頭文件,如果不加,怎么引用printf?這篇文章主題很好,但是內(nèi)容正確性讓人置疑!

    # re: C語(yǔ)言中的.h文件的作用  回復(fù)  更多評(píng)論   

    2014-12-16 20:42 by dodo
    文章是不錯(cuò)。但是內(nèi)容有錯(cuò)誤的。
    比如aaa.h文件里面包含的是aaa.c文件可以給外部調(diào)用的函數(shù)定義.
    而bbb.c文件要調(diào)用aaa.c里面的函數(shù),只需要包含aaa.h頭文件即可。
    而你講的方法是讓我們?cè)赽bb.h里面extern aaa.c里面的函數(shù)。這是不可取的。
    另外aaa.h不推薦定義了aaa.c文件里面所有的函數(shù)聲明,而只應(yīng)該聲明給外部調(diào)用的函數(shù)。不給外部調(diào)用的函數(shù)放在aaa.c文件頂部位置。

    # re: C語(yǔ)言中的.h文件的作用  回復(fù)  更多評(píng)論   

    2015-12-01 20:14 by asdf
    例程5什么亂碼七遭的,寫(xiě)完有沒(méi)有自己check,容易給人造成誤解

    # re: C語(yǔ)言中的.h文件的作用  回復(fù)  更多評(píng)論   

    2015-12-01 20:17 by asdf
    越往下看,越發(fā)現(xiàn)寫(xiě)的一團(tuán)混亂,完全看不懂,浪費(fèi)我10分鐘的時(shí)間,真垃圾啊
    主站蜘蛛池模板: 精品一卡2卡三卡4卡免费视频| 999zyz**站免费毛片| 亚洲综合国产一区二区三区| 国产免费观看视频| 亚洲AV无码一区二区乱孑伦AS| 亚洲人成电影青青在线播放| 无忧传媒视频免费观看入口| 99re6在线视频精品免费下载| 国产男女猛烈无遮档免费视频网站 | 亚洲一区AV无码少妇电影☆| 亚洲sss综合天堂久久久| 亚洲综合av一区二区三区| 美女被免费网站91色| 我要看免费的毛片| 亚洲成av人片天堂网| 国产精品亚洲专区一区| 1000部禁片黄的免费看| 久久精品亚洲福利| 国产亚洲福利在线视频| 久爱免费观看在线网站| 亚洲AV无码乱码在线观看| 亚洲成人黄色网址| 亚洲a∨无码一区二区| 看一级毛片免费观看视频| 久久WWW免费人成一看片| 无码国产精品一区二区免费I6| 国产亚洲精品看片在线观看| 亚洲国产欧美日韩精品一区二区三区| 免费h视频在线观看| www国产亚洲精品久久久日本| 亚洲一区二区三区91| 久久国产精品成人免费| 亚洲高清国产拍精品青青草原| 亚洲AV无码一区二区三区在线| 久久精品免费一区二区三区| 亚洲国产精品激情在线观看| 亚洲AV男人的天堂在线观看| 91麻豆国产免费观看| 日本红怡院亚洲红怡院最新| 日韩在线视频播放免费视频完整版| 午夜宅男在线永久免费观看网|