C\C++ 位域操作
幾篇較全面的位域相關的文章:
http://www.uplook.cn/blog/9/93362/
C/C++位域(Bit-fields)之我見
C中的位域與大小端問題
內存對齊全攻略–涉及位域的內存對齊原則
本文主要對位域相關知識進行了一下梳理,參考如下:
C語言中的位域
史上最全的C位域總結2
C結構體之位域(位段)
?
C/C++中以一定區域內的位(bit)為單位來表示的數據成為位域,位域必須指明具體的數目。
位域的作用主要是節省內存資源,使數據結構更緊湊。
1.?一個位域必須存儲在同一個字節中,不能跨兩個字節,故位域的長度不能大于一個字節的長度。
如一個字節所剩空間不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:
struct BitField{unsigned int a:4; //占用4個二進制位;unsigned int :0; //空位域,自動置0;unsigned int b:4; //占用4個二進制位,從下一個存儲單元開始存放;unsigned int c:4; //占用4個二進制位;unsigned int d:5; //占用5個二進制位,剩余的4個bit不夠存儲4個bit的數據,從下一個存儲單元開始存放;unsigned int :0; //空位域,自動置0;unsigned int e:4; //占用4個二進制位,從這個存儲單元開始存放;};2. 取地址操作符&不能應用在位域字段上;
3. 位域字段不能是類的靜態成員;
4.?位域字段在內存中的位置是按照從低位向高位的順序放置的;
struct BitField{unsigned char a:2; //最低位;unsigned char b:3;unsigned char c:3; //最高位;};union Union{struct BitField bf;unsigned int n;};union Union ubf;ubf.n = 0; //初始化;ubf.bf.a = 0; //二進制為: 000ubf.bf.b = 0; //二進制為: 000ubf.bf.c = 1; //二進制為: 001printf("ubf.bf.n = %u\n", ubf.n);位域中的位域字段按照從低位向高位順序方式的順序來看,那么,a、b、c這三個位域字段在內存中的放置情況是:
最高位是c:001,中間位是b:000,最低位是a:000;所以,這個位域結構中的8二進制內容就是: 00100000,總共8個位,其十進制格式就是32;
實際上打印出來的ubf.n值就是32;
ubf.n = 100; //二進制為: 01100100
printf("ubf.bf.a = %d, ubf.bf.b = %d, ubf.bf.c = %d\n", ubf.bf.a, ubf.bf.b, ubf.bf.c);
此時,對于位域ubf.bf來說,其位于字段仍然按照從低位向高位順序方式的順序放置,則,最高位是c:011,中間位是b:001,最低位是a:00;
所以,ubf.bf.a = 0; ubf.bf.b = 1; ubf.bf.c = 3;
實際上打印出來的結果也的確如此;不夠存儲下一個位域的4位,故設為空位域,不使用,自動置0;e從第四個字節處開始存放,占用4位;
5. 位域的對齊
1. 如果相鄰位域字段的類型相同,且其位寬之和小于類型的sizeof大小,則后面的字段將緊鄰前一個字段存儲,直到不能容納為止;
2. 如果相鄰位域字段的類型相同,但其位寬之和大于類型的sizeof大小,則后面的字段將從新的存儲單元開始,其偏移量為其類型大小的整數倍;
3.如果相鄰的兩個位域字段的類型不同,則各個編譯器的具體實現有差異,VC6采取不壓縮方式,GCC和Dev-C++都采用壓縮方式;
4. 整個結構體的總大小為最寬基本類型成員大小的整數倍。
5. 如果位域字段之間穿插著非位域字段,則不進行壓縮;(不針對所有的編譯器)
struct BFA{unsigned char a:2;unsigned char b:3;unsigned char c:3;};struct BFB{unsigned char a:2;unsigned char b:3;unsigned char c:3;unsigned int d:4; //多出來這個位域字段;};sizeof(BFA)=1, sizeof(BFB)=8;
這也說明了第三點中"相鄰兩個位于字段類型不相同時,VC6采取不壓縮的方式"
6.?當要把某個成員說明成位域時,其類型只能是int,unsigned int與signed int三者之一(說明:int類型通常代表特定機器中整數的自然長度。short類型通常為16位,long類型通常為32位,int類型可以為16位或32位.各編譯器可以根據硬件特性自主選擇合適的類型長度.見The C Programming Language中文 P32)。
盡管使用位域可以節省內存空間,但卻增加了處理時間,在為當訪問各個位域成員時需要把位域從它所在的字中分解出來或反過來把一值壓縮存到位域所在的字位中.
#include <iostream>#include <memory.h>using namespace std;struct A{int a:5;int b:3;};int main(void){char str[100] = "0134324324afsadfsdlfjlsdjfl";struct A d;memcpy(&d, str, sizeof(A));cout << d.a << endl;cout << d.b << endl;return 0;}在32位x86機器上輸出:
高位 00110100 00110011 00110001 00110000 低位'4' '3' '1' '0' 其中d.a和d.b占用d低位一個字節(00110000),d.a : 10000, d.b : 001解析:在默認情況下,為了方便對結構體內元素的訪問和管理,當結構體內的元素長度都小于處理器的位數的時候,便以結構體里面最長的元素為對其單位,即結構體的長度一定是最長的數據元素的整數倍;如果有結構體內存長度大于處理器位數的元素,那么就以處理器的位數為對齊單元。由于是32位處理器,而且結構體中a和b元素類型均為int(也是4個字節),所以結構體的A占用內存為4個字節。
上例程序中定義了位域結構A,兩個個位域為a(占用5位),b(占用3位),所以a和b總共占用了結構A一個字節(低位的一個字節)。
當程序運行到14行時,d內存分配情況:
高位 00110100 00110011 00110001 00110000 低位'4' '3' '1' '0'
其中d.a和d.b占用d低位一個字節(00110000),d.a : 10000, d.b : 001
?d.a內存中二進制表示為10000,由于d.a為有符號的整型變量,輸出時要對符號位進行擴展,所以結果為-16(二進制為11111111111111111111111111110000)
?d.b內存中二進制表示為001,由于d.b為有符號的整型變量,輸出時要對符號位進行擴展,所以結果為1(二進制為00000000000000000000000000000001)
?
另一個例子,來自http://blog.chinaunix.net/uid-28697486-id-3511598.htm
#include "stdio.h"void main(int argn ,char *argv) {struct test {unsigned a:10;unsigned b:10;unsigned c:6;unsigned :2;//this two bytes can't useunsigned d:4;}data,*pData;data.a=0x177;data.b=0x111;data.c=0x7;data.d=0x8;pData=&data;printf("data.a=%x data.b= %x data.c=%x data.d=%xn",pData->a,pData->b,pData->c,pData->d);//位域可以使用指針printf("sizeof(data)=%dn",sizeof(data)); //4 bytes ,最常用的情況struct testLen{char a:5;char b:5;char c:5;char d:5;char e:5;}len;printf("sizeof(len)=%dn",sizeof(len)); //5bytes 規則2struct testLen1{char a:5;char b:2;char d:3;char c:2;char e:7;}len1;printf("sizeof(len1) =%dn",sizeof(len1)); //3bytes 規則1struct testLen2{char a:2;char :3;char b:7;long d:20; //4byteschar e:4;}len2;printf("sizeof(len2)=%dn",sizeof(len2)); //12 規則3,4,5,總長為4的整數倍,2+3 占1byte,b占1bye 由于與long對其,2+3+7 占4字節,后面 d 與 e進行了優化 占一個4字節struct testLen3{char a:2;char :3;char b:7;long d:30;char e:4;}len3;printf("sizeof(len3)=%dn",sizeof(len3));//12 規則3,4,5,總長為4的整數倍,2+3 占1byte,b占1bye 由于與long對其,2+3+7 占4字節,后面 d占一個4字節,為了保證與long對其e獨占一個4字節 }?
另:C++標準庫提供了一個bitset 類模板,它可以輔助操縱位的集合。在可能的情況下應盡可能使用它來取代位域。
轉載于:https://www.cnblogs.com/soso-z/p/5781940.html
總結
以上是生活随笔為你收集整理的C\C++ 位域操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1045: 愚人节的礼物
- 下一篇: 《OD大数据实战》MongoDB环境搭建