當(dāng)前位置:首頁 > 公眾號精選 > wenzi嵌入式軟件
[導(dǎo)讀]筆者能力有限,如文中出現(xiàn)錯(cuò)誤的地方,還請各位朋友能給我指出來,我將不勝感激,謝謝~ 位域的概念 位域(或者也能稱之為位段,英文表達(dá)是 Bit field)是一種數(shù)據(jù)結(jié)構(gòu),可以把數(shù)據(jù)以位元的形式緊湊的存儲(chǔ),并允許程序員對此結(jié)構(gòu)的位元進(jìn)行操作。這種數(shù)據(jù)結(jié)構(gòu)

筆者能力有限,如文中出現(xiàn)錯(cuò)誤的地方,還請各位朋友能給我指出來,我將不勝感激,謝謝~

位域的概念

位域(或者也能稱之為位段,英文表達(dá)是 Bit field)是一種數(shù)據(jù)結(jié)構(gòu),可以把數(shù)據(jù)以位元的形式緊湊的存儲(chǔ),并允許程序員對此結(jié)構(gòu)的位元進(jìn)行操作。這種數(shù)據(jù)結(jié)構(gòu)的好處是:

  • 可以使數(shù)據(jù)單元節(jié)省存儲(chǔ)空間,當(dāng)程序需要成千上萬個(gè)數(shù)據(jù)單元時(shí),這種數(shù)據(jù)結(jié)構(gòu)的優(yōu)點(diǎn)也就很明顯地突出出來了。

  • 位段可以很方便地訪問一個(gè)整數(shù)值的部分內(nèi)容從而簡化程序源代碼。

位域的定義

總體來說位域的定義可以分為兩大類,一個(gè)是結(jié)構(gòu)體位域,一個(gè)是共用體體位域,由于共用體和結(jié)構(gòu)體兩者在定義上的形式都是相同的,因此對于位域的定義從形式上看,兩者也都是相同的。

結(jié)構(gòu)體位域

結(jié)構(gòu)體位域定義的一般形式如下所示:

   
  1. struct 位域結(jié)構(gòu)體名

  2. {

  3. 類型說明符 位域名 長度;

  4. }結(jié)構(gòu)體變量名;

舉個(gè)簡單的例子進(jìn)行說明:

   
  1. struct example0

  2. {

  3. unsigned char x : 3;

  4. unsigned char y : 2;

  5. unsigned char z : 1;

  6. }ex0_t;

上述定義是什么意思呢,用一張圖就能很清楚地明白,下圖是所定義的結(jié)構(gòu)體位域在內(nèi)存中的存儲(chǔ)位置:

從圖中我們可以看出,雖然 x 的類型是 unsigned char ,但是并沒有占 8 個(gè)位,而是占了 3 個(gè)位,其取值范圍也變成了 0 ~ 2^3-1。通過上述圖片我們也可以猜到這個(gè)結(jié)構(gòu)體位域的大小,筆者通過 printf 函數(shù)輸出結(jié)構(gòu)體位域的大小為:

   
  1. The Value of sizeof(ex0_t) is : 1 byte

關(guān)于結(jié)構(gòu)體位域的大小遵循這樣一個(gè)原則:整個(gè)結(jié)構(gòu)體位域的總大小為最寬基本類型成員大小的整數(shù)倍,這一原則與筆者在上一篇文章《結(jié)構(gòu)體內(nèi)存對齊解析》中寫的結(jié)構(gòu)體的總大小的原則是相同的。

共用體位域

共用體位域定義的一般形式跟結(jié)構(gòu)體定義的一般形式是大致相同的,直接舉一個(gè)簡單的例子進(jìn)行說明:

   
  1. union example1

  2. {

  3. unsigned char x : 3;

  4. unsigned char y : 2;

  5. unsigned char z : 1;

  6. }ex1_u;

同樣的,筆者在這里給出共用體位域在內(nèi)存中的存儲(chǔ)位置:

這里筆者也給出共用體位域的大小:

   
  1. The Value of sizeof(ex1_u) is : 1 byte

由此也可以得出共用體位域大小遵循的原則是:共用體位域的總大小為最大基本類型成員的大小

結(jié)構(gòu)體位域詳解

位域的類型使用無符號型

正如標(biāo)題所示,在位域的使用過程中使用無符號的數(shù)據(jù)類型,下面給出一個(gè)例子來說明這個(gè)例子:

   
  1. struct BitField_8

  2. {

  3. char a : 2;

  4. char b : 3;

  5. }BF8;


  6. BF8.a = 0x3;/* 11 */

  7. BF8.b = 0x5;/* 101 */

  8. printf("%d,%d\n",BF8.a,BF8.b);

上述的輸出結(jié)果為:

   
  1. -1,-3

輸出結(jié)果并不是我們想要的,究其原因,實(shí)際上是因?yàn)?BF.a ,BF.b 都是有符號的,那么自然也就有符號位的存在,而最高位為 1 代表負(fù)數(shù),負(fù)數(shù)又是以補(bǔ)碼的形式存儲(chǔ)在計(jì)算機(jī)中的,所以也就有了上述的結(jié)果。因此為了避免上述這種問題的出現(xiàn),應(yīng)該將 BitField_8 中的 char 轉(zhuǎn)換成 unsigned char ,那輸出的結(jié)果就是 3,5

位域禁止的操作

由于位域的特殊,同時(shí)也有了一些跟普通變量不同的特性:

  • 結(jié)構(gòu)體位域成員不能夠使用取址操作

   
  1. struct BitField_8

  2. {

  3. unsigned char a : 2;

  4. }BF8;

  5. printf("%p\n",&BF8.a); /*錯(cuò)誤*/

  • 結(jié)構(gòu)體位域成員不能夠用 static 修飾

   
  1. struct BitField_8

  2. {

  3. static unsigned char a : 2;/*錯(cuò)誤*/

  4. }BF8;

  • 結(jié)構(gòu)體位域成員不能夠使用數(shù)組

   
  1. struct BitField_8

  2. {

  3. unsigned char a[5] : 5;/*錯(cuò)誤*/

  4. }BF8;

不同處理器,不同編譯器對位域的影響

位域雖然能夠以位的形式操作數(shù)據(jù),但是也被人們告知要慎重使用,原因就在于不同的處理器結(jié)構(gòu),不同的編譯器對于位域的一些特性會(huì)產(chǎn)生不同的結(jié)果,這也就是位域移植性差的原因

處理器影響

處理器對位域造成的影響也很容易理解,大端模式和小端模式的處理器會(huì)對下面的結(jié)構(gòu)體位域產(chǎn)生不一樣的存儲(chǔ)方式,這里比較簡單,如果對這個(gè)問題不清楚的朋友可以看筆者的這篇文章《union 的概念及在嵌入式編程中的應(yīng)用》。

編譯器影響

結(jié)構(gòu)體位域成員不同類型

不同的編譯器對于位域會(huì)有不同的結(jié)果,比如下面這段代碼:

   
  1. struct BitField_5

  2. {

  3. unsigned int a : 4;

  4. unsigned char b : 4;

  5. }BF_8;


  6. int main(void)

  7. {

  8. printf("The Value of sizeof(BF_8) is:%lu bytes\n",sizeof(BF_8));

  9. }

上述所定義的結(jié)構(gòu)體位域中,對于結(jié)構(gòu)體位域內(nèi)成員不同數(shù)據(jù)類型,不同的編譯器有不同的處理,對于 Visual Studio 來說,面對不同的數(shù)據(jù)類型時(shí),對于上述這個(gè)例子,存儲(chǔ)完第一個(gè)成員 a 后,會(huì)重新另起 4 byte 的空間進(jìn)行存儲(chǔ),因此對于上述代碼在 Visual Studio 的運(yùn)行結(jié)果是:

   
  1. The Value of sizeof(BF_8) is 8 bytes

可見在 vs 環(huán)境下這樣使用位域不但沒有能夠節(jié)省內(nèi)存空間,反而相比于結(jié)構(gòu)體還擴(kuò)大了。上述是 VS 環(huán)境下的測試結(jié)果,下面是在 GCC 環(huán)境下的測試結(jié)果:

   
  1. The Value of sizeof(BF_8) is 4 bytes

可見在 GCC 環(huán)境下,就算結(jié)構(gòu)體位域成員的數(shù)據(jù)類型不一致,它其實(shí)按照“壓縮”數(shù)據(jù)的方式進(jìn)行存儲(chǔ)的,也就是說結(jié)構(gòu)體位域里的成員都是挨著存放的。

成員大小之和超過一個(gè)基本存儲(chǔ)空間

除了上述成員不同類型對于不同編譯器有不同的處理方式,當(dāng)成員大小之和超過一個(gè)基本存儲(chǔ)空間時(shí),不同的編譯器也有不同的處理方式,比如下面這段代碼:

   
  1. struct short_flag_t

  2. {

  3. unsigned short a : 7;

  4. unsigned short b : 10;

  5. };

對于上面這段代碼,同類型成員除了這樣定義之外,也可以這樣定義:

   
  1. struct short_flag_t

  2. {

  3. unsigned short a : 7,/*注意此處是逗號*/

  4. b : 10;

  5. };

上面的代碼因?yàn)?unsigned short 的大小是 2 個(gè)字節(jié),而成員 a,b加起來的大小已經(jīng)超過了 2 個(gè)字節(jié),所以這種情況下也就有了以下兩種存儲(chǔ)方式:

  • a , b 緊鄰

  • b 在下一個(gè)可存儲(chǔ)它的存儲(chǔ)單元內(nèi)分配內(nèi)存

不同編譯器可能面對這種情況會(huì)采用不同的存儲(chǔ)方式,對于 GCC 來說,采用的是第二種,如果編譯器采用的是第一種方式,而程序要求又需要按照第二種方式來進(jìn)行存儲(chǔ),又該如何辦呢?這時(shí)就要利用匿名 0 長度位域字段的語法強(qiáng)制位域在下一個(gè)存儲(chǔ)單元存儲(chǔ),示例代碼如下:

   
  1. struct short_flag_t

  2. {

  3. unsigned short a : 2;

  4. unsigned short : 0;

  5. unsigned short b : 3;

  6. }

上述代碼對于 a , b 來講,b 便不會(huì)緊挨著 a 進(jìn)行存儲(chǔ),而是強(qiáng)制使 b 在下一個(gè)存儲(chǔ)單元進(jìn)行存儲(chǔ)。

位域的應(yīng)用

上述便是位域涉及的基本概念,那知道了基本概念之后,又能使用位域做些什么呢?最容易另人想到的就是使用結(jié)構(gòu)體位域定義標(biāo)志位,由于我們在裸機(jī)開發(fā)的過程中,沒有信號量,事件等機(jī)制,通常會(huì)定義一些范圍只存在于 0~1 的開關(guān)量,而在沒有使用位域之前,最小的變量類型都是 1 個(gè)字節(jié),使用結(jié)構(gòu)體位域?qū)⒛軌蚋鶕?jù)取值范圍定義該變量的位數(shù),從而起到節(jié)省內(nèi)存的作用。

用于訪問微控制器的寄存器

位域受到處理器和編譯器的影響,在使用前我們必須清楚當(dāng)前處理器是大端對齊還是小端對齊,必須清楚當(dāng)前編譯器對所定義的位域有何影響

如果我們現(xiàn)在要使用位域訪問一個(gè) 8 位的寄存器,這個(gè)寄存器大致長這個(gè)樣子:

那么我們就可以使用結(jié)構(gòu)體位域構(gòu)造這樣一個(gè)數(shù)據(jù)結(jié)構(gòu):

   
  1. typedef union

  2. {

  3. unsigned char Byte;

  4. struct

  5. {

  6. unsigned char bit012 : 3;

  7. unsigned char bit34 : 2;

  8. unsigned char bit5 : 1;

  9. unsigned char bit6 : 1;

  10. unsigned char bit7 : 1;

  11. }bits;

  12. }registerType;

現(xiàn)在假設(shè)我們這個(gè)寄存器的地址是 0x0000 8000,那么我們就可以定義一個(gè)指針并使其指向這個(gè)地址,如下:

   
  1. registerType *pReg = (registerType *)0x0000 8000;

在進(jìn)行了上述定義之后,我們就可以對寄存器進(jìn)行操作了,首先,我們可以使用位域的方式操作寄存器的位,比如這樣:

   
  1. pReg->bits.bit5 = 1;

  2. pReg->bits.bit012 = 7;

當(dāng)然也可以利用 union 的特性直接操作整個(gè)寄存器,如下:

   
  1. pReg->Byte = 0x55;

使用位域完成對于寄存器的訪問,對于上述例子來講,我們必須要注意的一點(diǎn)是此例子是基于小端對齊模式的。

總結(jié)

位域的用法雖然看起來更加靈活了,但是在使用時(shí)也要對我們的處理器和編譯器有所了解,如果為了寫出移植性較高的程序,應(yīng)該避免使用位域。

參考資料:

[1] https://aticleworld.com/access-the-port-and-register-using-bit-field-in-embedded-c/

[2] https://www.raviyp.com/bitfields-in-c-for-accessing-microcontroller-registers/

[3]https://aticleworld.com/bit-field-in-c/

您的閱讀是對我最大的鼓勵(lì),您的建議是對我最大的提升,歡迎點(diǎn)擊下方圖片進(jìn)入小程序進(jìn)行評論,或者添加筆者微信相互交流,微信二維碼在公眾號底部進(jìn)行獲取



免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉