新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 嵌入式C語言中如何使用指針

        嵌入式C語言中如何使用指針

        作者: 時間:2007-04-24 來源:網(wǎng)絡(luò) 收藏

        本文引用地址:http://www.104case.com/article/258222.htm

        數(shù)據(jù)指針

          在嵌入式系統(tǒng)的編程中,常常要求在特定的內(nèi)存單元讀寫內(nèi)容,匯編有對應(yīng)的MOV指令,而除C/C++以外的其它編程語言基本沒有直接訪問絕對地址的能力。在嵌入式系統(tǒng)的實際調(diào)試中,多借助C語言指針?biāo)哂械膶^對地址單元內(nèi)容的讀寫能力。以指針直接操作內(nèi)存多發(fā)生在如下幾種情況:

          (1) 某I/O芯片被定位在CPU的存儲空間而非I/O空間,而且寄存器對應(yīng)于某特定地址;

          (2) 兩個CPU之間以雙端口RAM通信,CPU需要在雙端口RAM的特定單元(稱為mail box)書寫內(nèi)容以在對方CPU產(chǎn)生中斷;

          (3) 讀取在ROM或FLASH的特定單元所燒錄的漢字和英文字模。

          譬如:

        unsigned char *p = (unsigned char *)0xF000FF00;
        *p=11;

          以上程序的意義為在絕對地址0xF0000+0xFF00(80186使用16位段地址和16位偏移地址)寫入11。

          在使用絕對地址指針時,要注意指針自增自減操作的結(jié)果取決于指針指向的數(shù)據(jù)類別。上例中p++后的結(jié)果是p= 0xF000FF01,若p指向int,即:

        int *p = (int *)0xF000FF00;

          p++(或++p)的結(jié)果等同于:p = p+sizeof(int),而p-(或-p)的結(jié)果是p = p-sizeof(int)。

          同理,若執(zhí)行:

        long int *p = (long int *)0xF000FF00;

          則p++(或++p)的結(jié)果等同于:p = p+sizeof(long int) ,而p-(或-p)的結(jié)果是p = p-sizeof(long int)。

          記?。篊PU以字節(jié)為單位編址,而C語言指針以指向的數(shù)據(jù)類型長度作自增和自減。理解這一點對于以指針直接操作內(nèi)存是相當(dāng)重要的。



        函數(shù)指針

          首先要理解以下三個問題:

         ?。?)C語言中函數(shù)名直接對應(yīng)于函數(shù)生成的指令代碼在內(nèi)存中的地址,因此函數(shù)名可以直接賦給指向函數(shù)的指針;

          (2)調(diào)用函數(shù)實際上等同于調(diào)轉(zhuǎn)指令+參數(shù)傳遞處理+回歸位置入棧,本質(zhì)上最核心的操作是將函數(shù)生成的目標(biāo)代碼的首地址賦給CPU的PC寄存器;

         ?。?)因為函數(shù)調(diào)用的本質(zhì)是跳轉(zhuǎn)到某一個地址單元的code去執(zhí)行,所以可以調(diào)用一個根本就不存在的函數(shù)實體,暈?請往下看:

          請拿出你可以獲得的任何一本大學(xué)《微型計算機原理》教材,書中講到,186 CPU啟動后跳轉(zhuǎn)至絕對地址0xFFFF0(對應(yīng)C語言指針是0xF000FFF0,0xF000為段地 址,0xFFF0為段內(nèi)偏移)執(zhí)行,請看下面的代碼:



        typedef void (*lpFunction) ( ); /* 定義一個無參數(shù)、無返回類型的 */
        /* 函數(shù)指針類型 */
        lpFunction lpReset = (lpFunction)0xF000FFF0; /* 定義一個函數(shù)指針,指向*/
        /* CPU啟動后所執(zhí)行第一條指令的位置 */
        lpReset(); /* 調(diào)用函數(shù) */


          在以上的程序中,我們根本沒有看到任何一個函數(shù)實體,但是我們卻執(zhí)行了這樣的函數(shù)調(diào)用:lpReset(),它實際上起到了軟重啟的作用,跳轉(zhuǎn)到CPU啟動后第一條要執(zhí)行的指令的位置。

          記?。汉瘮?shù)無它,唯指令集合耳;你可以調(diào)用一個沒有函數(shù)體的函數(shù),本質(zhì)上只是換一個地址開始執(zhí)行指令!

          數(shù)組vs.動態(tài)申請

          在嵌入式系統(tǒng)中動態(tài)內(nèi)存申請存在比一般系統(tǒng)編程時更嚴(yán)格的要求,這是因為嵌入式系統(tǒng)的內(nèi)存空間往往是十分有限的,不經(jīng)意的內(nèi)存泄露會很快導(dǎo)致系統(tǒng)的崩潰。

          所以一定要保證你的malloc和free成對出現(xiàn),如果你寫出這樣的一段程序:



        char * function(void)
        {
         char *p;
         p = (char *)malloc(…);
         if(p==NULL)
          …;
          … /* 一系列針對p的操作 */
         return p;
        }


          在某處調(diào)用function(),用完function中動態(tài)申請的內(nèi)存后將其free,如下:



        char *q = function();

        free(q);



          上述代碼明顯是不合理的,因為違反了malloc和free成對出現(xiàn)的原則,即誰申請,就由誰釋放原則。不滿足這個原則,會導(dǎo)致代碼的耦合度增大,因為用戶在調(diào)用function函數(shù)時需要知道其內(nèi)部細(xì)節(jié)!

          正確的做法是在調(diào)用處申請內(nèi)存,并傳入function函數(shù),如下:



        char *p=malloc(…);
        if(p==NULL)
        …;
        function(p);

        free(p);
        p=NULL;



          而函數(shù)function則接收參數(shù)p,如下:



        void function(char *p)
        {
         … /* 一系列針對p的操作 */
        }


          基本上,動態(tài)申請內(nèi)存方式可以用較大的數(shù)組替換。對于編程新手,筆者推薦你盡量采用數(shù)組!嵌入式系統(tǒng)可以以博大的胸襟接收瑕疵,而無法海納錯誤。畢竟,以最笨的方式苦練神功的郭靖勝過機智聰明卻范政治錯誤走反革命道路的楊康。

          給出原則:

         ?。?)盡可能的選用數(shù)組,數(shù)組不能越界訪問(真理越過一步就是謬誤,數(shù)組越過界限就光榮地成全了一個混亂的嵌入式系統(tǒng));

         ?。?)如果使用動態(tài)申請,則申請后一定要判斷是否申請成功了,并且malloc和free應(yīng)成對出現(xiàn)!



        評論


        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 昭平县| 桐城市| 赫章县| 靖江市| 淮安市| 永和县| 万年县| 潮安县| 昌吉市| 乌兰县| 平湖市| 寿光市| 东海县| 柘荣县| 沁阳市| 富阳市| 杭州市| 保亭| 通海县| 卫辉市| 文化| 拉萨市| 黎城县| 乌鲁木齐县| 博爱县| 津南区| 开封市| 肥乡县| 安仁县| 永宁县| 富裕县| 惠东县| 赤峰市| 浦城县| 西和县| 专栏| 玉田县| 大连市| 信丰县| 霍山县| 莱芜市|