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

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

位域的概念

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

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

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

位域的定義

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

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

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

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

  2. {

  3. 類型說(shuō)明符 位域名 長(zhǎng)度;

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

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

   
  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 ,但是并沒(méi)有占 8 個(gè)位,而是占了 3 個(gè)位,其取值范圍也變成了 0 ~ 2^3-1。通過(guò)上述圖片我們也可以猜到這個(gè)結(jié)構(gòu)體位域的大小,筆者通過(guò) 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)存對(duì)齊解析》中寫的結(jié)構(gòu)體的總大小的原則是相同的。

共用體位域

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

   
  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ǔ)位置:

這里筆者也給出共用體位域的大?。?/p>

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

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

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

位域的類型使用無(wú)符號(hào)型

正如標(biāo)題所示,在位域的使用過(guò)程中使用無(wú)符號(hào)的數(shù)據(jù)類型,下面給出一個(gè)例子來(lái)說(shuō)明這個(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 都是有符號(hào)的,那么自然也就有符號(hào)位的存在,而最高位為 1 代表負(fù)數(shù),負(fù)數(shù)又是以補(bǔ)碼的形式存儲(chǔ)在計(jì)算機(jī)中的,所以也就有了上述的結(jié)果。因此為了避免上述這種問(wèn)題的出現(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;

不同處理器,不同編譯器對(duì)位域的影響

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

處理器影響

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

編譯器影響

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

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

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

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

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

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

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

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

   
  1. struct short_flag_t

  2. {

  3. unsigned short a : 7;

  4. unsigned short b : 10;

  5. };

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

   
  1. struct short_flag_t

  2. {

  3. unsigned short a : 7,/*注意此處是逗號(hào)*/

  4. b : 10;

  5. };

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

  • a , b 緊鄰

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

不同編譯器可能面對(duì)這種情況會(huì)采用不同的存儲(chǔ)方式,對(duì)于 GCC 來(lái)說(shuō),采用的是第二種,如果編譯器采用的是第一種方式,而程序要求又需要按照第二種方式來(lái)進(jìn)行存儲(chǔ),又該如何辦呢?這時(shí)就要利用匿名 0 長(zhǎng)度位域字段的語(yǔ)法強(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. }

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

位域的應(yīng)用

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

用于訪問(wèn)微控制器的寄存器

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

如果我們現(xiàn)在要使用位域訪問(wèn)一個(gè) 8 位的寄存器,這個(gè)寄存器大致長(zhǎng)這個(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)行了上述定義之后,我們就可以對(duì)寄存器進(jìn)行操作了,首先,我們可以使用位域的方式操作寄存器的位,比如這樣:

   
  1. pReg->bits.bit5 = 1;

  2. pReg->bits.bit012 = 7;

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

   
  1. pReg->Byte = 0x55;

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

總結(jié)

位域的用法雖然看起來(lái)更加靈活了,但是在使用時(shí)也要對(duì)我們的處理器和編譯器有所了解,如果為了寫出移植性較高的程序,應(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/

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



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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