日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(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)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動(dòng)電源

在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢抑制與過流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

電動(dòng)汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車的動(dòng)力性能和...

關(guān)鍵字: 電動(dòng)汽車 新能源 驅(qū)動(dòng)電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

關(guān)鍵字: LED 驅(qū)動(dòng)電源 開關(guān)電源

LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
關(guān)閉