日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

嵌入式開發(fā)中,C語言位結(jié)構(gòu)體用途詳解

 西北望msm66g9f 2019-01-28

在嵌入式開發(fā)中,經(jīng)常需要表示各種系統(tǒng)狀態(tài),位結(jié)構(gòu)體的出現(xiàn)大大方便了我們,尤其是在進(jìn)行一些硬件層操作和數(shù)據(jù)通信時。但是在使用位結(jié)構(gòu)體的過程中,是否深入思考一下它的相關(guān)屬性?是否真正用到它的便利性,來提高系統(tǒng)效率?


下面將進(jìn)行一些相關(guān)實(shí)驗(yàn)(這里以項(xiàng)目開發(fā)中的實(shí)際代碼為例):


1.位結(jié)構(gòu)體類型設(shè)計(jì)

[cpp] view plain copy print?

1. //data structure except for number structure  

2. typedef struct symbol_struct  

3. {  

4. uint_32 SYMBOL_TYPE     :5;  //data type,have the affect on 'data display type'  

5. uint_32 reserved_1      :4;  

6.   

7. uint_32 SYMBOL_NUMBER  :7;  //effective data number in one element  

8. uint_32 SYMBOL_ACTIVE  :1;//symbol active status  

9.   

10. uint_32 SYMBOL_INDEX   :8;  //data index in norflash,result is related to 'xxx_BASE_ADDR'  

11. uint_32 reserved_2     :8;  

12.   

13. }SYMBOL_STRUCT,_PTR_ SYMBOL_STRUCT_PTR;  


分析:這里定義了一個位結(jié)構(gòu)體類型SYMBOL_STRUCT,那么用該類型定義的變量都哪些屬性呢?

看下面運(yùn)行結(jié)果:

 


WORDS是定義的另一個外層類型定義封裝,可以把它當(dāng)作變量來看待。WORDS變量里前5個數(shù)據(jù)域的地址都是0x1ffff082c,而reserved_2的地址0x1fff0830,緊接著的PressureState變量是0x1fff0834。

開始以為:reserved_1和SYMBOL_TYPE不在一個地址上,因?yàn)樗麄?+4共9位,超過了1個字節(jié)地址,但實(shí)際他們共用首地址了;而且reserved_2只定義了8位,竟然實(shí)際占用了4個字節(jié)(0x1fff0834 - 0x1fff0830),我本來是想讓他占用1個字節(jié)的。WORDS整體占了8個字節(jié)(0x1fff0834 - 0x1fff082c),設(shè)計(jì)時分析占用5個字節(jié)


(SYMBOL_TYPE 1個;reserved_1 1個;SYMBOL_NUMBER+SYMBOL_ACTIVE 1個;SYMBOL_INDEX 1個;reserved_2 1個)。


uint_32  reserved_2   : 8;  占用4個字節(jié),估計(jì)是uint_32在起作用,而這里寫的8位,只是我使用的有效位數(shù),另外24位空閑,如果在下面再定義一個uint_32  reserved_3   : 8,地址也是一樣的,都是以uint_32為單位取地址。


同理,上面的5個變量,共用一個地址就不足為奇了。而且有效位的分配不是連續(xù)進(jìn)行的,例如SYMBOL_TYPE+reserved_1 共9位,超過了一個字節(jié),索性系統(tǒng)就分配兩個字節(jié)給他們,每人一個;SYMBOL_NUMBER+SYMBOL_ACTIVE 共8位,一個字節(jié)就能搞定。


2、修改數(shù)據(jù)結(jié)構(gòu),驗(yàn)證上述猜想


[cpp] view plain copy print?

1. //data structure except for number structure  

2.    typedef struct symbol_struct  

3.    {  

4.    uint_8 SYMBOL_TYPE    :5;  //data type,have the affect on 'data display type'  

5.    uint_8 reserved_1     :4;  

6.      

7.    uint_8 SYMBOL_NUMBER   :7;  //effective data number in one element  

8.    uint_8 SYMBOL_ACTIVE   :1; //symbol active status  

9.      

10.    uint_8 SYMBOL_INDEX    :8;  //data index in norflash,result is related to 'xxx_BASE_ADDR'  

11.    uint_8 reserved_2      :8;  

12.      

13.    }SYMBOL_STRUCT,_PTR_ SYMBOL_STRUCT_PTR;  

14.     

地址數(shù)據(jù)如下:



當(dāng)換成uint_8后,可以看到地址空間占用大大減小,reserved_2只占用1個字節(jié)(0x1fff069f - 0x1fff069e),其他變量也都符合上面的結(jié)論猜想。但是,注意看上面黃色和紅色的語句,總感覺有些勉強(qiáng),那么我又會想,前兩個變量數(shù)據(jù)域是9位,那么他們實(shí)際上是不是真正的獨(dú)立呢?雖然在uint_8上面他們是不同的地址,在uint_32的時候是不是也是不同的地址空間呢?

 

3、分析結(jié)構(gòu)體內(nèi)部的數(shù)據(jù)域是否連續(xù),看下圖及結(jié)果

 

本來假設(shè): 由前2次試驗(yàn)的結(jié)論,一共占用8個字節(jié),節(jié)空間占用:(2+4)+(4+4)+(2+2+4)+(2+2)+(6)。可是,實(shí)際效果并不是想的那樣。實(shí)際只占用了4個字節(jié),系統(tǒng)并沒有按照預(yù)想的方式,為RESERVED變量分配4個字節(jié)。


分析:

這些數(shù)據(jù)域,整體相加一共32位,占用4個字節(jié)(不考慮數(shù)據(jù)對齊問題)。而實(shí)際確實(shí)是占用了4個字節(jié),唯一的原因就是:這些數(shù)據(jù)域以緊湊的方式鏈接,沒有任何空閑位。實(shí)際是不是這樣呢?


看下圖和結(jié)果:

 

這里為了驗(yàn)證是否緊湊鏈接,用到了一個union數(shù)據(jù),后面會講到用union不會對數(shù)據(jù)組織方式有任何影響,看實(shí)際與上次的一樣,也能分析出來。


主要是分析第2和第3個數(shù)據(jù)域是否緊密鏈接的。OBJECT_ACTIVE_PRE賦值0b00001111,NUMBER_ACTIVE賦值0b00000101,其他變量都是0,看到WORD數(shù)值0b1011111000000。分析WORD數(shù)據(jù),可以看到這款MCU還是小端格式(高位數(shù)據(jù)在高端,低位數(shù)據(jù)在低端,這里不對大小端進(jìn)行討論),斷開數(shù)據(jù)變成(0)10111 11000000,正好是0101+1111,OBJECT_ACTIVE_PRE數(shù)據(jù)域,跨越了兩個字節(jié),并不是剛開始設(shè)想的那樣。這就印證了上面的緊密鏈接的結(jié)論,也符合數(shù)據(jù)結(jié)果輸出。

 

4、再次實(shí)驗(yàn),分析數(shù)據(jù)是否緊密鏈接,看下圖和結(jié)果

 

可以看到,RESERVED數(shù)據(jù)域已經(jīng)不再屬于4個地址空間內(nèi)了(0x1fff0518 - 0x1fff051b),但是他們整體加起來還是32個位域。這說明數(shù)據(jù)中間肯定有“空隙”存在了,空隙在哪?看一下NUMBER_STATE,如果緊密的話它應(yīng)該跟NUMBER_ACTIVE在同一個字節(jié)地址上,可是他們并不在一塊,“空隙”就存在這里。


這兩個結(jié)構(gòu)體有什么不一樣?數(shù)據(jù)類型不一致,一個是uint_32,一個是uint_8。綜上所述:數(shù)據(jù)類型影響的是編譯器在分配物理空間時的大小單位,uint_32是以4個字節(jié)為單位,而后面的位域則是指在已經(jīng)分配好的物理空間內(nèi)部再緊湊的方式分配數(shù)據(jù)位,當(dāng)物理空間不能滿足位域時,那么系統(tǒng)就再次以一定大小單位進(jìn)行物理空間分配,這個單位就是上面提到的uint_8或者uint_32。


舉例:上面uint_32時,這些位域不管是不是在一個字節(jié)地址上,如果能夠緊湊的分配在一個4字節(jié)空間大小上,就直接緊湊分配。如果不能則繼續(xù)分配(總空間超過4字節(jié)),則再次以4字節(jié)空間分配,并把新的位域建立在新的地址空間上(條目1上的就是)。當(dāng)uint_8時,很明顯如果位域不能緊湊的放在一個字節(jié)空間上,那么就從新分配新的1字節(jié)空間大小,道理是一樣的。

 

5、結(jié)構(gòu)體組合、共用體組合是否影響上述結(jié)論

 


可以看到,系統(tǒng)并沒有因?yàn)槲唤Y(jié)構(gòu)體上面有uint_4的4字節(jié)變量或者共用體類型,就改變分配策略把位域都擠到4字節(jié)之內(nèi),看來他們是沒有什么實(shí)質(zhì)性聯(lián)系的。這里把uint_32改成uint_8,或者把位結(jié)構(gòu)體也替換掉,經(jīng)我試驗(yàn)證明,都是沒有任何影響的。

 

總結(jié):


1、在操作位結(jié)構(gòu)體時,要關(guān)注變量的位域是否在一個變量類型(uint_32或者uint_8)上,判斷占用空間大小


2、除了位域,還要關(guān)注變量定義類型,因?yàn)榫幾g器空間分配始終是按類型分配的,位域只是指出了有效位(小于類型占用空間),而且如果位域大于類型空間,編譯器直接報(bào)錯(如 uint_8  test  :15,可自行實(shí)驗(yàn))。


3、這兩個因素都影響變量占用空間大小,具體可以結(jié)合調(diào)試窗口,通過地址分配分析判斷


4、最重要的一點(diǎn):上面的所有結(jié)果,都是基于我自己的CodeWarrior10.2和MQX3.8分析出來的,不同的編譯環(huán)境和操作系統(tǒng),都可能會有不同的結(jié)果;而且即便是環(huán)境相同,編譯器的配置和優(yōu)化選項(xiàng)都有可能影響系統(tǒng)處理結(jié)果。結(jié)論并不重要,主要想告訴大家這一塊隱藏陷阱,在以后處理類似問題時,要注意分析避讓并掌握方法。



    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多