溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C語言結構體的位域是什么

發(fā)布時間:2021-11-22 14:56:42 來源:億速云 閱讀:562 作者:iii 欄目:互聯(lián)網(wǎng)科技

本篇內容主要講解“C語言結構體的位域是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“C語言結構體的位域是什么”吧!

我們之前講結構體的時候,都是用int,char之類的數(shù)據(jù)類型來定義結構體的成員變量的,這些成員變量都有一個共性,就是他們的長度都是一個字節(jié),或者一個的偶數(shù)倍。然而我們在存儲某些信息時,并不需要一個完整的,而是只需要讓這個變量占據(jù)一個或者幾個二進制位。

可能有些讀者會想,那我直接使用一個字節(jié)的長度來存儲這些幾位的變量即可,雖然會浪費一些存儲空間,但是這些位的浪費對于現(xiàn)在的一些計算機或者單片機來說都是無關緊要的。確實,當我們定義一個變量的時候,對于目前計算機強大的硬件來說,定義以一個幾個位的變量和定義一個幾個字節(jié)的變量確實沒有任何影響,反而字節(jié)單位變量比位變量有更大的存儲空間,可以有效地防止長度溢出。

但是,當面對下面這種應用時,字節(jié)單位變量不僅沒有任何好處,反而會大大增加我們程序的操作難度。如,在一個單片機系統(tǒng)中有一個寄存器。假設這個寄存器的長度為一個字節(jié),它的功能是用來控制一個單片機的定時器以及反應一個定時器的狀態(tài),這個寄存器的第7,6位表示定時器的狀態(tài)位TIM_STAT[1:0],第5,4,3,2位表示定時器時鐘源的分頻系數(shù)TIM_DIV[3:0],第1位表示定時器的溢出標志TIM_OVERFLOW,第0位表示定時器的工作開關TIM_START/STOP。具體這個假設的寄存器如圖1所示。

C語言結構體的位域是什么

圖1 某寄存器

面對上面的這種應用,我們一般的做法就是定義一個unsigned char類型的變量Tim_Ctrl,然后進行位操作,比如要將TIM_STAT賦值狀態(tài)0b11,那我們就可以使用位操作語句,“Tim_Ctrl |= 0b11000000;”,如果要將TIM_STST賦值狀態(tài)0b00,就使用位操作語句“Tim_Ctrl &= ~(b11000000);”,這種微操作的方式非常繁瑣,而且直觀性很差。

那是否有一種數(shù)據(jù)類型可以支持這種位數(shù)比較少的變量呢?比如直接可以定義一個兩位的變量,然后賦值狀態(tài)0b11即可。在C語言中,常規(guī)的變量明顯是不支持這種操作的,但是在結構體中卻支持。這種C語言結構體中支持位操作的方式被稱為“位域”,或者“位段”。

位段(或稱“位域”,Bit field)為一種數(shù)據(jù)結構,可以把數(shù)據(jù)以位的形式緊湊的儲存,并允許程序員對此結構的位進行操作。這種數(shù)據(jù)結構的好處:

  • 可以使數(shù)據(jù)單元節(jié)省儲存空間,當程序需要成千上萬個數(shù)據(jù)單元時,這種方法就顯得尤為重要。

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

  • 而位域這種數(shù)據(jù)結構的缺點在于,其內存分配與內存對齊的實現(xiàn)方式依賴于具體的機器和系統(tǒng),在不同的平臺可能有不同的結果,這導致了位段在本質上是不可移植的。

位域的定義是在結構體中定義的時候完成的,其定義方式如下:

struct

{

  數(shù)據(jù)類型 變量名 :位長度;

  數(shù)據(jù)類型 變量名 :位長度;

} status;

比如,對于上面這個定時器的寄存器,我們可以定義如下:

struct

{

     unsigned char TIM_START_STOP : 1;

      unsigned char TIM_OVERFLOW : 1;

      unsigned char TIM_DIV : 4;

      unsigned char TIM_STAT : 2;

} register;

注意,這樣定義好之后,整個結構體的位域定義時都是從低地址開始的。因此,當一個位域被定義好之后,其內存的分布如圖2所示。

C語言結構體的位域是什么

圖2 位域內存分配

一旦當位域定義好之后,比如圖2中的TIM_DIV,它所占用的比特數(shù)為4bits,因此雖然我們定義它的時候是用unsigned char類型去定義的,但是它最多能表示的二進制數(shù)只有4位,即范圍為:0x00~0x0F。一旦當我們賦值超過了次范圍,這個變量就會將多余的高位數(shù)據(jù)舍棄。

我們可以寫一個程序來論證,按照圖1所示的寄存器位分布,定義結構體位域變量,接著給它賦一個超出它長度的值,然后打印出來看看輸出。如圖3所示。

C語言結構體的位域是什么

圖3 結構體位域成員超出范圍

從圖3中我們可以看出,一旦當某個位域成員超出其位數(shù)大小之后,編譯器先會拋出一個警告,然后將這個變量打印出來的值也是不對。那么為什么我們賦值20,卻輸出一個4呢?這是因為20的二進制數(shù)是0b00010100,而由于TIM_DIV變量只占有4個bit的存儲空間,因此超出的部分會被舍棄,最終只保留低4位0b0100,因此這個變量打印出來的值為4。

由于這個結構體變量是占一個字節(jié)的存儲空間,因此我們可以用一個指針打印出這個存儲空間的全部內容。操作也很簡單,我們只需定義一個unsignedchar類型的指針,并且使結構體的地址強行轉換為一個“unsigned char *”類型,然后用指針指向它,最后引用指針將這個地址打印出來,就可以看到這個結構體全貌了。具體操作如圖4所示。

C語言結構體的位域是什么

圖4 結構體數(shù)據(jù)

為什么最后結果是0xA7呢?因為整個結構體按照位域賦值之后如圖5所示,最后轉換成十六進制就是0xA7了。

C語言結構體的位域是什么

圖5 位域賦值之后

到此,相信大家對“C語言結構體的位域是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI