C语言自定义类型——位段
位段
?
目錄
位段
一、定義
二、注意事項
1、位段成員必須是整型家族的(int ,unsigned int ,char 等)。
2、位段成員名后可跟冒號加一個數字來表示它占有幾個比特位
三、位段的內存分配
四、具體空間開辟(截斷)
五、位段的跨平臺問題
?
C語言中有很多的自定義類型,我在以前的博客中已經講過了結構體和結構體的內存對齊,現在我們來講另一個自定義類型,就是位段。
一、定義
位段,C語言允許在一個結構體中以比特位為單位來指定其成員所占內存長度,這種以位為單位的成員稱為“位段”或稱“位域”( bit field) 。利用位段能夠用較少的位數存儲數據。
可以看出位段和結構體很像,下面我們引入一段代碼片段來看一下位段到底長什么樣子。
struct A{int a : 2;//成員a占2個比特位int b : 5;//成員b占5個比特位int c : 10;//成員c占10個比特位int d : 30;//成員d占30個比特位 };二、注意事項
1、位段成員必須是整型家族的(int ,unsigned int ,char 等)。
可以看見,這里如果是float類型的成員,編譯器會直接報錯。
整型家族的數組也不行哦,編譯器也會報錯。
2、位段成員名后可跟冒號加一個數字來表示它占有幾個比特位
正如我們在? 一、定義? 時的代碼片段,但是其實一個位段的部分成員也可以不加冒號和數字(如果全部成員都不加冒號和數字了它就變成結構體了)。
例如上圖,我們也是不會錯的。
三、位段的內存分配
在window環境下的VS編譯器中,位段的內存分配是按照這種規則的:根據首個成員變量的類型分配相應字節的內存(例如:首個成員是 int 類型的,則分配4個字節即32個比特位的空間大小),然后根據成員的實際大小(也就是:后面的數字)來填充這個已經分配的空間,若剩余的空間不夠了,則繼續根據成員類型依次分配內存并且填充(分配內存時要注意內存對齊,如果不知道什么是內存對齊,可以看我以前寫的博客,填充時不用對齊),直到該位段的最后一個成員,需要注意的是,整個位段的大小是成員類型大小中最大值的整數倍。
上面的概念過于復雜,我們來看一個例子:
第一步,分配,根據第一個成員的類型分配4字節即32位大小的內存;
第二步,填充,因為a,b,c成員的大小加起來為27位,而d成員為6位,所以這塊被分配的內存只能填充a,b,c(這里的填充是反向填充,即從該區域的最后端開始依次填充a,b,c);
第三步,分配,根據接下來的成員也就是 char 型的 d 分配一個字節8個比特位的空間,根據內存對齊判斷,該空間緊貼上一個分配的空間即可;
第四步,填充,這塊空間只夠填充成員 d ;
第五步,分配,并判斷內存對齊,應根據 int 型變量 e 分配4個字節的空間,但根據內存對齊這段被分配的空間不能緊挨著成員 d ,應該間隔3個字節再分配(對齊到該成員對齊數整數倍的位置上);
第六步,填充,這個空間只夠填充成員 e 占用其中的30位;
第七步,根據成員 f?的 char 型分配一個字節的空間,根據內存對齊規則,該區域可以緊貼上一個區域,然后將最后一個成員填充進去;
第八步,根據內存對齊規則的最后一條,也就是整個位段的大小是成員類型大小中最大值的整數倍,所以我們必須還要在余出3個字節;
所以,位段A的內存分布情況為下圖:
sizeof(struct A)=5+3+4+1+3=16字節。
下面來驗證一下:
四、具體空間開辟(截斷)
看一個具體的例子:
struct S{char a : 3;char b : 4;char c : 5;char d : 4; };struct S s = { 0 }; s.a = 10; s.b = 12; s.c = 3; s.d = 4;由于位段的成員的大小被重新分配,例如成員 a 占3個比特位,它的范圍應該是 0 到 7 ,而這里給 a 賦值為10,應該如何處理呢?這里的操作我稱作為截斷
請看下面我畫出的內存圖,更為直觀
驗證:這是VS中內存的部分
和我們的分析一致。
五、位段的跨平臺問題
位段在不同的平臺上有不同的規則:
1、int 位段被當成有符號數還是無符號數是不確定的。
2、位段中的成員從左到右分配還是從右到左分配是不確定的。
3、當一個結構包含兩個位段,第二個位段成員比較大,無法容納第一個位段剩余的位時,是舍棄剩余的位還是利用,也是不確定的。
所以跟結構體相比,位段更節省空間,但是有跨平臺的問題。
?
?
這就是今天和大家分享的內容了,希望大家一起提高,共同進步!!!
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的C语言自定义类型——位段的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于mfc实现画图软件
- 下一篇: OpenSSL笔记-PKCS#1和PKC