C語言快速掌握位段使用
一、位段是什么
位段的聲明和結(jié)構(gòu)是類似的,有兩個不同
1.位段的成員必須是 int、unsigned int 或signed int 。
2.位段的成員名后邊有一個冒號和一個數(shù)字。
舉例如下:
struct A { int _a:2; int _b:5; int _c:10; int _d:30; };
這個A就是一個位段。
但是結(jié)構(gòu)體可以根據(jù)結(jié)構(gòu)體內(nèi)存對齊確定一個結(jié)構(gòu)體的大小,但是位段的大小怎么確定呢?
位段A的大小是多少呢?
printf("%d\n", sizeof(struct A));
我們利用sizeof操作符來測一下這個A位段的大小是8個字節(jié)
但是根據(jù)常理來說應該是16個字節(jié)呀,我們和結(jié)構(gòu)體對比分析
struct s { int a; int b; int c; int d; }; int main() { printf("%d\n", sizeof(struct s));//16個字節(jié) return 0; }
對比發(fā)現(xiàn)位段不是根據(jù)他的數(shù)據(jù)類型來分配內(nèi)存的。接下來我們看看位段是怎么分配內(nèi)存的。
二、位段的內(nèi)存分配
2.1位段內(nèi)存分配的原則
- 位段的成員可以是 int unsigned int signed int 或者是 char (屬于整形家族)類型
- 位段的空間上是按照需要以4個字節(jié)( int )或者1個字節(jié)( char )的方式來開辟的。
- 位段涉及很多不確定因素,位段是不跨平臺的,注重可移植的程序應該避免使用位段。ps:雖然位段是不跨平臺的,但是我們可以根據(jù)平臺的不同編寫不同的代碼
struct A { int _a:2; //雖然a是int型但是他所分配的內(nèi)存根據(jù)冒號之后的數(shù)字確定,a冒號后面是2,所以他只占用2個比特位 int _b:5; //同理,b成員只需要5個比特位 int _c:10; //10個比特位 int _d:30; //30個比特位 };
那么我們發(fā)現(xiàn)這個字段A一共需要47個比特位,好像6個字節(jié)就可以完成存儲,但是事實并非如此,我們根據(jù)位段的內(nèi)存分配原則,位段的成員是int類型所以按照需要以4個字節(jié)的方式開辟,我們先開辟4個字節(jié)的空間,即32個比特位,我們可以存儲a,b,c但是存儲d的時候發(fā)現(xiàn)內(nèi)存不夠了,我們再次按照需求再一次開辟4個字節(jié)的空間,最終開辟了8個字節(jié)的空間而非6個字節(jié)的空間來存儲位段A。
但是a,b,c存儲之后還剩下15個比特位,這些比特位還用不用呢?
答案是不確定的,每個編譯器的處理方式都是不一樣的,在VS環(huán)境下就浪費掉了,位段依舊有很多的不確定性。下面用圖例理想表示一下在VS環(huán)境下位段的存儲:
代碼如下:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> struct S { char a : 3; //a占3個比特位,以下同理 char b : 4; char c : 5; char d : 4; }; int main() { //printf("%d\n", sizeof(struct S)); struct S s = { 0 }; s.a = 10; // 賦值給位段的成員 s.b = 12; s.c = 3; s.d = 4; return 0; }
2.2位段內(nèi)存分配圖解
假設內(nèi)存都是由低位向高位使用的,即從右向左使用:
我們將這3個字節(jié)的內(nèi)存中都用0進行初始化:
struct S s = {<!--{C}%3C!%2D%2D%20%2D%2D%3E--> 0 };
三、位段的跨平臺問題
int 位段被當成有符號數(shù)還是無符號數(shù)是不確定的。
int的最高位原本是符號位,但是int位段是有符號數(shù)還是無符號數(shù)是不確定的。位段中最大位的數(shù)目不能確定。(16位機器最大16,32位機器最大32,寫成27,在16位機器會出問題。
(16位機器最大可以處理16位數(shù)據(jù),尋址空間也只有16位,但是如果傳入27位數(shù)據(jù)就會出問題)
ps:int在16位操作系統(tǒng)下占2個字節(jié)。位段中的成員在內(nèi)存中從左向右分配,還是從右向左分配標準尚未定義。
上圖只是假設我們從右向左使用,但是分配表示尚未定義,所以也是不確定的。當一個結(jié)構(gòu)包含兩個位段,第二個位段成員比較大,無法容納于第一個位段剩余的位時,是舍棄剩余的位還是利用,這是不確定的。
總結(jié):
跟結(jié)構(gòu)相比,位段可以達到同樣的效果,但是可以很好的節(jié)省空間,但是有跨平臺的問題存在。
犧牲了它的可移植性,但是節(jié)省了空間,可以根據(jù)需求選擇。
為什么說和結(jié)構(gòu)相比,位段可以節(jié)省空間呢?
代碼如下(示例):
struct A { int _a:2; //雖然a是int型但是他所分配的內(nèi)存根據(jù)冒號之后的數(shù)字確定,a冒號后面是2,所以他只占用2個比特位 int _b:5; //同理,b成員只需要5個比特位 int _c:10; //10個比特位 int _d:30; //30個比特位 };
比如這個代碼,假設a的取值只可能是0,1,2,3,如果用結(jié)構(gòu)寫的話會給a分配4個字節(jié)的空間也就是32個比特位,但是a最大需要的比特位是2位,所以會大大造成浪費,并且結(jié)構(gòu)體還存在結(jié)構(gòu)體內(nèi)存對齊問題,犧牲了空間提高了時間效率。
四、位段的使用
總結(jié)
位段的介紹到此結(jié)束,總結(jié)一下就是位段相比較結(jié)構(gòu)體節(jié)省了空間但是失去了可移植性,存在了跨平臺的問題,我們可以根據(jù)自身的需求來選擇是否使用位段,同時位段廣泛使用在計算機網(wǎng)絡方面,如果想變強就需要學會合理使用位段,加油 少年們!
到此這篇關于C語言快速掌握位段使用的文章就介紹到這了,更多相關C語言位段內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++實現(xiàn)主機字節(jié)序和網(wǎng)絡字節(jié)序轉(zhuǎn)換示例
這篇文章主要為大家介紹了C++實現(xiàn)主機字節(jié)序和網(wǎng)絡字節(jié)序轉(zhuǎn)換示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11Qt圖形圖像開發(fā)曲線圖表模塊QChart庫縮放/平移詳細方法與實例
這篇文章主要介紹了Qt圖形圖像開發(fā)曲線圖表模塊QChart庫縮放/平移詳細方法與實例,需要的朋友可以參考下2020-03-03Embarcadero?Dev-C++輸出中文亂碼問題圖文詳解
Dev-C++(或者叫做 Dev-Cpp)是Windows環(huán)境下的一個輕量級C/C++ 集成開發(fā)環(huán)境(IDE),下面這篇文章主要給大家介紹了關于Embarcadero?Dev-C++輸出中文亂碼問題的相關資料,需要的朋友可以參考下2023-01-01一篇文章帶你實現(xiàn)C語言中常用庫函數(shù)的模擬
這篇文章主要介紹了C語言中常用庫函數(shù)的模擬,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09C++如何實現(xiàn)BitMap數(shù)據(jù)結(jié)構(gòu)
這篇文章主要介紹了C++如何實現(xiàn)BitMap數(shù)據(jù)結(jié)構(gòu),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07