Effective C++: BitField

位域是指在信息存儲時候並不須要一個完整的字節,只須要佔用一個或幾個二進制位。ios

例如:存放一個開關量的時候,只有0和1兩種狀態,用一位二進制位表示就好了。工具

所謂位域,就是把一個字節(8位)中的二進制位分爲幾個不一樣的區域,並說明幾個區域的位數.測試

須要注意的是:this

1,位域的類型必須是整型或枚舉類型spa

2,一個位域字段必須小於等於一個字節(8位). 若是當前字節所剩下的空間不足以存儲下一個位域字段指定的位域的時候,從下一個字節開始存儲接着存儲.咱們也能夠手動指出從下一個直接開始存儲.code

3,取地址操做符不能用到位域字段上。ip

4,位域字段不能是類的靜態成員.內存

5,位域字段在內存中的位置是按照從低位到高位的順序放置的(針對intel CPU也就是little-endian).get

6,別的CPU多是按照big-endian放置數據到位域字段中的。編譯器

7,(wiki)https://en.wikipedia.org/wiki/Endianness

 

#include <iostream>
#include <iostream>

//intel:  little-endian
class BitField { //BitField中的a,b,c,d,e表示位域字段.
private:
	unsigned int a : 4; //最低位  //  0<= a <= 15;
	unsigned int b : 3;           //  0<= b <= 7;
	unsigned int c : 1;           //  0<= c <=1;
	unsigned int d : 4;           //  0<= d <= 15;
	unsigned int e : 4; //最高位  //  0<= e <=15;

	unsigned int f : 2;         // 0<= f <=3;
	unsigned int : 0;           //這裏指出即便當前字節沒有存滿,也會從下一個字節開始存儲.
	unsigned int g : 8;        // 0<= g <=255


public:

	BitField();

	~BitField()=default;

	void setBit();

	void print()const noexcept;

};

BitField::BitField()
	/*:a(1)
	 b(2)
	 c(1)
	 d(3) //不能這麼初始化.
	e(4) */
{
	//
}

void BitField::setBit()
{
	this->a = 1;
	this->b = 1;
	this->c = 1;
	this->d = 1;
	this->e = 1;

	this->f = 1;
	this->g = 1;
}

void BitField::print()const noexcept
{
	std::cout << this->a << " "
		<< this->b << " "
		<< this->c << " "
		<< this->d << " "
		<< this->e << " "
		<< this->f << " "
		<< this->g << std::endl;
}

int main()
{
	BitField f;
	f.setBit();
	f.print();

	return 0;
}

位域的內存對齊:

1,若是相鄰位域字段的類型相同,且位寬之和的大小 小於該類型sizeof的大小,則後面的位域將緊鄰前面位域名存儲,直到該字節已經不能容納爲止.

2,若是相鄰位域字段的類型相同,且位寬之和的大小 大於該類型的sizeof的大小,則後面的位域將開闢一個新的字節進行存儲.

3,若是相鄰的位域字段的類型不相同,是否採起壓縮方式要看編譯器了。

4,若是位域字段之間穿插着非位域的字段,則不採用壓縮。

5,整個位域結構體的sizeof大小,爲結構體內最寬類型成員的整數倍.

 

Demo 1:

//測試工具: vs2015, x64模式.
//intel:  little-endian

struct BF {
	unsigned char a1 : 5;
	unsigned char a2 : 5;
	unsigned char a3 : 5;
	unsigned char a4 : 5;
	unsigned char a5 : 5;
};

int main()
{

    //輸出: 1(字節)
	std::cout << "unsigned char: " << sizeof(unsigned char) << std::endl;

    //輸出: 4(字節)
	std::cout << "BF: " << sizeof(BF) << std::endl;
    //BF中的位域表面上是一共佔用了25個二進制位,不夠4個字節,可是又多於3個字節
    //這樣一來編譯器就會自動填充位,足夠4個字節.
    

	return 0;
}

Demo 2:

//測試工具: vs2015, x86
//intel:  little-endian


struct BF {
	unsigned char a1 : 5;
	unsigned char a2 : 5;
	long int      a3 : 5; //注意這裏的long int類型.
	unsigned int  a4 : 5;
	unsigned char a5 : 5;
};

int main()
{

    //輸出: 1(字節)
	std::cout << "unsigned char: " << sizeof(unsigned char) << std::endl;

    //輸出: 4(字節)
	std::cout << "long int: " << sizeof(long int) << std::endl;

    //輸出: 12(字節)
	std::cout << "BF: " << sizeof(BF) << std::endl;
    //a1 和 a2只佔了10位不夠2個字節,可是a3是個long int 類型是4個字節
    //a1 和 a2就會補位到4個字節以便於和 a3對齊.到這裏就4個字節了.
    //a3佔了4個字節,到這裏就8個字節了.
    //a4 和 a5佔用了10位不夠2個字節補位到與long int的位數相同也就是4個字節,到這裏就佔用了12個字節了.

	return 0;
}
相關文章
相關標籤/搜索