位域操作


看runtime源碼時,看到如下聲明變量的,變量后分號前加冒號和數字": 數字"即為位域操作。

uintptr_t indexed           : 1;

 

1個字節包含8位,有些變量保存的數據不需要占用這么長的空間(比如bool類型,只有兩個狀態true和false, 1位就可以搞定,剩下的7位就浪費了),這就催生了“位域”結構,位域將1個字節划分成不同的區域,每個區域都有個位域名(可以理解為變量名,上邊的代碼中位域名為indexed),程序員可以代碼通過位域名訪問其中的數據。

 

一. 聲明

 
         
類型說明符 位域名:位域長度;
 
        

 

位域結構體,我理解是一種特殊的結構體,其成員變量都是位域,聲明如下

 

struct 位域結構名 {
  類型說明符 位域名:位域長度;
  類型說明符 位域名:位域長度;
  類型說明符 位域名:位域長度;
  ...
  類型說明符 位域名:位域長度;
};

  

二. 基本原則

1. 位域變量的長度不能大於其類型的長度(sizeof(類型) * 8)

變量char has_assoc的類型位char 1字節 8位,小於定義的10,所以編譯器警告

 

2.  不能用於位域字段的操作:取地址操作符&,取偏移量操作

位域是若干位空間,是沒有地址的

 

 

3. 位域可以是無名位域,無名位域只能用作填充或調整位置,不能使用。如下圖結構體S007的最后一個變量就是無名位域,無法使用

 

4. 位域字段不能聲明為類的靜態成員

 

5. 位域結構體的大小必須是其最長基本類型大小的整數倍(sizeof(類型) * 8)

 

三. 內存分配規則

1. 判斷大小端,以我自己的機子為例,不同環境下有可能不同

 

定義聯合體U007和位域結構體S007,將U007實例u7的number賦值31,二進制為 | 0000 0000 | 0000 0000 | 0000 0000 | 0001 1111 |,根據存儲原則,數值都是從高地址往低地址讀,因此位域結構體S007中的位域變量是從低地址開始分配內存的,即

 

2. 位域變量類型相同

位域變量長度之和小於[sizeof(變量類型)*8], 則后面的位域字段將緊鄰前一個字段存儲, 直到不能容納為止

位域變量長度之和大於[sizeof(變量類型)*8], 則后面的位域字段將從下一個存儲單元的起始地址處開始存放(其偏移量恰好為sizeof(變量類型)的整數倍)

 

位域結構體S007的3個成員變量都是unfigned short類型,sizeof(unfigned short)*8 = 16位,

a0占1位,從起始地址分配1位;

a1占9位,a0+a1=10位,小於16位(sizeof(unfigned short)*8),因此a1在a0后連續分配9位;

a2占15位,(a0 + a1) + a2 = 25位,大於16位,因此跳過6位,在S007起始地址偏移量為16位的地方,給a2分配15位。

再次提醒:小端是分配內存地址時從低地址開始,但是變量的數值是從高地址往低地址讀

 

3. 位域變量類型不同時,各個編譯器的具體實現有差異,VC6采取不壓縮方式,GCC和Dev-C++都采用壓縮方式,以下是我自己機子的處理方式

 

位域結構體S007的前2個成員變量unfigned char類型(sizeof(unfigned char)*8 = 8位),后一個成員變量unfigned short(sizeof(unfigned short)*8 = 16位)

 

a占2位,從起始地址分配2位;

b占3位,a+b=5位,小於8位(sizeof(unfigned char)*8,b的類型是unfigned char),因此b在a后連續分配3位;

c占15位,(a + b) + c = 20位,大於16位(sizeof(unfigned short)*8,c的類型是unfigned short),因此跳過11位,在S007起始地址偏移量為16位的地方,給c分配15位。

 

有上圖可以看出,在我的機子上,如果位域變量的類型不同,仍會進行內存壓縮(如果需要跳位,判斷哪個位域變量,就用該變量的類型進行偏移量對齊判斷)

 

 4. 如果位域變量之間穿插着非位域變量, 則不進行壓縮

非位域變量也可以理解為特殊的位域變量,只不過占的位數是變量長度,即 類型 位域名 : sizeof(類型)*8

根據規則3,則無法進行內存壓縮

 

位域結構體S007的第2個成員變量char tmp;是非位域變量,轉成位域變量為 char tmp:8;

 

a占2位,從起始地址分配2位;

tmp占8位,a+tmp=10位,大於8位(sizeof(char)*8,tmp的類型是char),因此跳過6位,在S007起始地址偏移量為8位的地方,給tmp分配8位;

b占3位,在tmp后給b分配3位。

 

 

5. 上邊舉的例子中參數都是unsigned標識的,如果帶上符號位會是什么情況呢?

關於帶符號基本類型變量在內存中存儲方式,請看這里http://www.cnblogs.com/xieyajie/p/8125214.html

 

位域結構體S008定義了2個帶符號位域變量,a0占2位,a1占3位

a0是帶符號short類型,內存中保存的是補碼11,首位符號位為1,負數,推出源碼為11,轉為十進制為-1;

a1是帶符號short類型,內存中保存的是補碼001,首位符號位為0,正數,源碼為001,轉為十進制為1。

 

如果a0只占1位會怎么樣?從測試結果可以看出,這1位幾十符號位,也是數值位


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM