嵌入式開(kāi)發(fā)C語(yǔ)言問(wèn)題詳解_第1頁(yè)
嵌入式開(kāi)發(fā)C語(yǔ)言問(wèn)題詳解_第2頁(yè)
嵌入式開(kāi)發(fā)C語(yǔ)言問(wèn)題詳解_第3頁(yè)
已閱讀5頁(yè),還剩5頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、嵌入式開(kāi)發(fā) C 語(yǔ)言問(wèn)題詳解2021年嵌入式開(kāi)發(fā)C語(yǔ)言問(wèn)題詳解嵌入式系統(tǒng)的 C 語(yǔ)言開(kāi)發(fā)中,經(jīng)常遇到這樣那樣的問(wèn)題。有些問(wèn)題可能很快就能找到原因, 但是有些問(wèn)題必須有一定的經(jīng)驗(yàn)積累才 能快速找到原因。一、由編譯優(yōu)化引起的問(wèn)題例1、編譯后的匯編語(yǔ)言處理邏輯跟 C語(yǔ)言處理邏輯不一致由于編譯器的原因,在設(shè)置了編譯優(yōu)化的情況下,編譯后有些代 碼的邏 輯會(huì)發(fā)生變化。這種情況下會(huì)發(fā)生很奇怪的問(wèn)題,一些函數(shù) 的處理結(jié)果跟預(yù) 想的不一致,而檢查代碼又看不出什么問(wèn)題。這種問(wèn)題的解決方法一般是在充分分析軟件處理邏輯,確認(rèn)處理 上沒(méi)問(wèn) 題后,把編譯后的列表文件(*. lis)和C語(yǔ)言處理邏輯逐行對(duì) 照。把不一致 的

2、地方找出來(lái),并尋找修正對(duì)策。例 2、編譯后的一些處理被優(yōu)化了這種問(wèn)題經(jīng)常發(fā)生在硬件存放器的操作上。對(duì)于硬件而言,每一 次讀寫(xiě) 操作可能都有特定的含義: 某些硬件存放器要求讀一下才能 做后續(xù)其他處理 ; 而某些存放器要連續(xù)寫(xiě)幾次。比方下面的情形:#defineTSTREG(unsignedchar*)0x00C00032/*TESTREGISTER*/un sig nedcha"pTSTR;pTSTR二 TSTREG;*pTSTR二0x01; /這個(gè)操作很容易被編譯器優(yōu)化掉。*pTSTR=0x02;作為對(duì)策之一,可以在定義變量時(shí)加上 volatile 關(guān)鍵字。比方volatileuns

3、ignedchar*pTSTR;聲明的變 量表示volatile 關(guān)鍵詞影響編譯器編譯的結(jié)果, 用 volatile該變量隨時(shí)可能發(fā)生變化,與該變量有關(guān)的運(yùn)算,不要進(jìn)行 編譯優(yōu)化,以免 出錯(cuò)。使用 volatile 變量的幾個(gè)場(chǎng)景:1) 中斷效勞程序中修改的供其它程序檢測(cè)的變量需要加volatile2) 多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加 volatileo3) 存儲(chǔ)器映射的硬件存放器通常也要加 voliate, 因?yàn)槊看螌?duì)它 的讀 寫(xiě)都可能有不同意義。、由字節(jié)對(duì)齊引起的問(wèn)題一個(gè)結(jié)構(gòu)體變量定義完之后,其在內(nèi)存中的存儲(chǔ)并不一定等于其 所包含 元素的寬度之和。因?yàn)檫@里涉及到字節(jié)對(duì)齊的問(wèn)題。結(jié)構(gòu)體

4、中元素的對(duì)齊基木上遵循兩個(gè)根本原那么:原那么一:結(jié)構(gòu)體中元素是按照定義順序一個(gè)一個(gè)放到內(nèi)存中去的 , 但并不 是緊密排列的。從結(jié)構(gòu)體存儲(chǔ)的首地址開(kāi)始,每一個(gè)元素放 置到內(nèi)存中時(shí), 它都會(huì)認(rèn)為內(nèi)存是以它自己的大小來(lái)劃分的,因此 元素放置的位置一定會(huì)在 自己寬度的整數(shù)倍上開(kāi)始(以結(jié)構(gòu)體變量首 地址為 0 計(jì)算) O原那么二:在經(jīng)過(guò)第一原那么分析后,檢查計(jì)算出的存儲(chǔ)單元是否為 所有元 素中最寬的元素的長(zhǎng)度的整數(shù)倍。假設(shè)是,那么結(jié)束 ; 假設(shè)不是,那么 補(bǔ)齊為它的整 數(shù)倍。每個(gè)特定平臺(tái)上的編譯器都有自己的默認(rèn)“對(duì)齊系數(shù)(也叫對(duì) 齊模數(shù) 或邊界調(diào)整數(shù)) 。通常, 可以通過(guò)預(yù)編譯命令 #pragmapac

5、k(n), n 二 1, 2, 4, 8, 16 來(lái)改變這一系數(shù),其中的 n 就是你要指定的“對(duì)齊系 數(shù)。ftpragmapack ( n)/ 編譯器將按照 n 字節(jié)對(duì)齊#pragmapack()/ 編譯器將取消自定義字節(jié)對(duì)齊方式在#pragmapack (n)禾口#pragmapack ()之問(wèn)的代碼按 n字節(jié)對(duì)齊。 但是成員對(duì)齊有一個(gè)重要的條件,即每個(gè)成員按照自己的對(duì)齊方式 對(duì)齊; 也就 是說(shuō)雖然指定了按 n 字節(jié)對(duì)齊,但并不是所有的成員都以 n 字節(jié)對(duì)齊。對(duì)齊 的規(guī)那么是:每個(gè)成員按其類型的對(duì)齊參數(shù) 通常是 這個(gè)類型的大小 和指定對(duì) 齊參數(shù) 這里是 n 字節(jié) 中較小的一個(gè)對(duì)齊 , 即 m

6、inn, sizeof item, 并 且結(jié)構(gòu)的長(zhǎng)度必須為所用過(guò)的所有對(duì) 齊參數(shù)的整數(shù)倍,不夠就補(bǔ)空字節(jié)。以瑞薩SH7145FCP和XASS-V編譯器為例,根據(jù) XASS-V幫助文 件, 對(duì)于SH7145F,其結(jié)構(gòu)體成員的默認(rèn)對(duì)齊系數(shù)如下:char : 1short : 2int : 4long : 4float : 4longlong : 4double : 4指針: 4結(jié)構(gòu)體 / 聯(lián)合體: 4數(shù)組:根據(jù)類型而定在編譯的時(shí)候可以通過(guò)設(shè)置 /bond 二 n, n 二 4 一般情況 , 來(lái)指定邊 界 調(diào)整系數(shù)。因此,實(shí)際采用 /bond 二 n 中的 n 和上述默認(rèn)對(duì)齊系數(shù) 中的較小 者。由于

7、跟特定編譯器有關(guān),所以下而的例子僅限XASS-V編譯器,目標(biāo)CPU 是瑞薩 SH7145Fo例 1 、假設(shè) /bond 二 4, 進(jìn)行如下定義 :typedefunsignedcharUCHAR;/* 結(jié)構(gòu)體定義 */typedefstructunionUCHARSO_bit7;UCHARDMY0_bit56;UCHARLNO_bitO4;DL;/* 預(yù)想 BYTEO*/UCHARORDN;unionUCHARRW_bit7;UCHARDTN0_bit06;RD;/* 預(yù)想 BYTE1VUCHARADRH; /預(yù)* 想 BYTE2*/UCHARADRL; /*預(yù)想 BYTE3*/UCHARDA

8、TA; /*預(yù)想 BYTE4*/stTEST;/* 變量定義 */UCHARTEST6;錯(cuò)誤stTEST*pTEM二(stTEST*) TEST;這樣執(zhí)行后,pTEM->ADR并不是對(duì)應(yīng)TEST3,導(dǎo)致了數(shù)據(jù)處理原因分析 :由邊界調(diào)整數(shù)決定, union 只能在 4 的倍數(shù)的地址上存放 ; 且UNION類型要占用4*XByte,故后面有3Byte的DummyO卩 UNIONxxxDL 占用了 4Byteo依次類推,整個(gè)結(jié)構(gòu)體元素的內(nèi)存分布如下:UNION xxx DL; /*ByteOByte3: 后 3ByteDummy*/UCHARORDN; /*Byte4AByte7:后 3Byt

9、eDummy*/UNIONxxx RD; AByteSABytell:后 3ByteDummy*/UCHARADRH;/*Bytel2*/UCHARADRL;/*Bytel3*/UCHARDATA; /*Bytel4ABytel5: 后 lByteDummy*/Byte5"Byte7的Dumm是因?yàn)閁NION成員必須在4的倍數(shù)的地址 上存 放。Bytel5的Dumm是整個(gè)結(jié)構(gòu)休大小必須是 4的倍數(shù)。所以 sizeof(stTEST)=16, pTEM->ADRH 對(duì)應(yīng)為 Bytel2, 不是預(yù) 想 的 .TEST 3 。三、由變量類型不匹配引起的問(wèn)題例 1、循環(huán)變量溢出UCHA

10、Ri=0x00;/* 版本 1: 100 個(gè)循環(huán) */for(i=0;i 100;i+) /* 處理:略 */* 版本 2: 1000 個(gè)循環(huán) */for(i=0;i<1000;i+) /* 處理:略 */一開(kāi)始需求是 100 個(gè)循環(huán),而后而需求變更為 1000 個(gè)循環(huán),但 忘記修改循環(huán)變量類型。以為 UCHA的有效范圍是0、255,顯然不滿足版木2的要求。這種情況會(huì)發(fā)生在循環(huán)變量定義的位置距離循環(huán)體比擬遠(yuǎn)的時(shí)候,在無(wú)意識(shí)中忽略了。四、由數(shù)組下標(biāo)越界引起的問(wèn)題常見(jiàn)的是指定的數(shù)組下標(biāo)超過(guò)了數(shù)組最大有效下標(biāo)。很多情況下不會(huì)導(dǎo)致程序奔潰,但是取出的數(shù)據(jù)顯然是不正確的。五、由字節(jié)序主要表達(dá)大于I

11、Byte的數(shù)據(jù)的存儲(chǔ)方式上。對(duì)于 CPU而言,有 MSBFIRST和 LSBFIRST兩種存儲(chǔ)方式。MSB MostSign 辻 icantBit, 即 最高有效位;LSB指LestSign辻icantBit,即最低有效位。簡(jiǎn)單地說(shuō),MSBFIRS就是高位優(yōu)先存儲(chǔ),即高位存儲(chǔ)在低地址上,低位存儲(chǔ)在高地址上,簡(jiǎn)稱“上下低高。LSBFIRST那么相反,即低位優(yōu)先存儲(chǔ),高位存儲(chǔ)在高地址上,低位存 儲(chǔ)在低地址上,簡(jiǎn)稱“高上下低。大局部嵌入式系統(tǒng)的 CPU是 MSBFIRST勺,少局部是 LSBFIRST的。常見(jiàn)的 LSBFIRST的 CPL是 INTEL 的。類似的,在網(wǎng)絡(luò)通信方面有兩種字節(jié)序:“Bi

12、g -Endian 和"Small-Endian"。指的都是對(duì)于多字節(jié)的數(shù)據(jù)類型 (比方4字節(jié)的32位整 數(shù)),其多個(gè)字節(jié)的順序問(wèn)題,是最高字節(jié)在前(Big-Endian) 還是最低字節(jié)在前(Small-Endian)°比方對(duì)于123456789這個(gè)整數(shù),其16進(jìn)制為0X075BCD15那么按照Big-Endian的方式,它在網(wǎng)絡(luò) 上傳輸(或者在內(nèi)存 里存儲(chǔ))的4個(gè)字節(jié)依次是:075BCD15而Small-Endian的順序正相反, 是:15CD5B07處J?通信的雙方必須 按相同的字節(jié)序進(jìn)行收發(fā)數(shù)據(jù)處理, 才能得出正常的結(jié)果。例1、應(yīng)用程序 A以075BCD1啲

13、字節(jié)序(Big-Endian)發(fā)送數(shù)據(jù) 123456789給應(yīng)用程序B,但應(yīng)用程序B卻以15CD5B07的字節(jié)序 (Small-E ndia n)處理,那么雙方?jīng)]法正常通信。六、由UNION元素賦值引起的問(wèn)題一個(gè)UNION元素的值由最后那次設(shè)定決定的。有些時(shí)候,無(wú)意中 對(duì)一個(gè) UNION元素連續(xù)賦值,就會(huì)發(fā)生意料之外的問(wèn)題。例1、以前面的結(jié)構(gòu)體類型 stTEST為例,做如下設(shè)置。stTESTtTst; tTst. DL. SO_bit7=OxSO;ASO 使用 bit7*/tTst. DL. LNO_bitO4 二 0x01 ;/*LNO 使用 bit0bit4*/ 這樣設(shè)置后,最終 S0=0

14、, 而不是預(yù)先希望的 SO=1。七、由運(yùn)算符優(yōu)先級(jí)引起的問(wèn)題 運(yùn)算符優(yōu)先級(jí)處理不好也會(huì)引入一些潛在的問(wèn)題。例 1、邏輯運(yùn)算符與條件運(yùn)算符inta=0x02;辻( (a&0x03) ! =0x00) /* 表達(dá)式 1*/if (a&0x03! =0x00) /* 表達(dá)式 2*/表達(dá)式1:先執(zhí)行0x02&0x03=>0x02,再執(zhí)行0x02! =0x00,故結(jié) 果為T(mén)RUEo表達(dá)式 2: 先執(zhí)行 0x03! 二 0x00 二 TRUE (結(jié)果是 0x01), 再執(zhí)行 0x02&0x01, 結(jié)果為 0x00 即 FALSEo顯然,表達(dá)式 1 才是正確的寫(xiě)法。如果

15、把用表達(dá)式 2 的形式就會(huì) 引入一 些潛在的問(wèn)題。例 2、指針取值運(yùn)算,邏輯運(yùn)算符與條件運(yùn)算符if (*pSTSRG&0x01)二=0x00) /* 表達(dá)式 1*/ 辻( (*pSTSRG) &0x01) =0x00) /* 表達(dá)式 2*/ if (* pSTSRG&0x01=0x00)/表達(dá)式 3*/ 顯然,表達(dá)式 1 和表達(dá)式 2 是正確寫(xiě)法, 而且最保險(xiǎn)的寫(xiě)法是表 達(dá)式 2。而表達(dá)式 3 是錯(cuò)誤寫(xiě)法。 從上而的例子可以看出,由于運(yùn)算符優(yōu)先級(jí)不太方便記憶,也沒(méi) 必要去記憶,最躲避這類問(wèn)題的最好方法就是給表達(dá)式強(qiáng)制加上括 號(hào)。八、由中斷優(yōu)先級(jí)引起的問(wèn)題在多線程應(yīng)用程序

16、開(kāi)發(fā)中,經(jīng)常會(huì)用信號(hào)量等方式來(lái)保證共享資 源的訪 問(wèn)。但是在有多個(gè)中斷的應(yīng)用程序中,經(jīng)常會(huì)無(wú)意識(shí)地略掉 中斷優(yōu)先級(jí),導(dǎo) 致引入一些潛在的問(wèn)題。例1、中斷IRQ1每1ms發(fā)生1次,中斷IRQ4每4ms發(fā)生1次,且IRQ4 的優(yōu)先級(jí)高于IRQIo在IRQ1和IRQ4的處理過(guò)程都會(huì)設(shè)置 全局變量tDatao 該如何安排IRQ1和IRQ4的處理邏輯?因?yàn)榈蛢?yōu)先級(jí)的中斷 IRQ1 未處理完成時(shí), 如果發(fā)生高優(yōu)先級(jí)的 中斷 IRQ4, 那么IRQ1的處理會(huì)把相關(guān)上下文壓棧,暫時(shí)掛起,等IRQ4處理完成后才繼續(xù)處理IRQIo由于IRQ4也會(huì)修改全局變量tData,如果沒(méi)有任何保護(hù)措施,那么 IRQ1 的處理可能會(huì)不完全正確。 作為對(duì)策之一就是在 IRQ1 的處理中參加中 斷屏蔽。AIRQ1 的中斷處理函數(shù) */IRQI_HandIer()XXX;/* 屏蔽所有中斷 */yyy;/* 相關(guān)處理 */ZZZ;/* 解除中斷屏蔽 */當(dāng)然,上述處理的前提是IRQ4是可屏蔽中斷。九、由匯編語(yǔ)言轉(zhuǎn)C語(yǔ)言引起的問(wèn)題由于CPU的更換,原先用匯編語(yǔ)言開(kāi)發(fā)

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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)論