1. 程式人生 > >C++標準庫bitset型別

C++標準庫bitset型別

    bitset用於處理二進位制位集。是一種類模板。

#include<bitset>
using std::bitsset

1. 定義和初始化

      在定義bitset時,要明確bitset是多少位,須在尖括號中制定它的長度值。

bitset<32> bitvec;

給定的長度必須是常量表達式,也即必須定義為整型字面值常量或const物件。

  (1). 用unsigned之初始化bitset物件

        unsigned long值將轉換為二進位制的位模式,若bitset型別長度大於unsigned long的二進位制位數,則其餘高階位置0;若小於,則使用unsigned long的低階位,超過bitset的高階位被丟棄。

注:低階位-高階位

bitset:在32位的bitset物件上為例,以0開始的位串是低階位(low-order bit),以31 位結束的位串是高階位(hight-order bit)。

word(機器字):在32位的unsigned long機器上,在不同體系結構的機器上應該有不同的儲存方式。引自英文原版C++ Primer 4中【On a machine with 32-bit unsigned long s, the hexadecimal value 0xffff is represented in bits as a sequence of 16 ones followed by 16 zeroes. (Each 0xf digit is represented as 1111 .)】所說的儲存方式為低位元組在前,高位元組在後。以0xffff為例,在機器內的儲存方式為:11111111111111110000000000000000,從低階-->高階。

關鍵概念:計算機的記憶體儲存方式

計算機的記憶體儲存方式由CPU決定,不過為了相容性,現在AMD和INTEL都是用相同的方式存放:低位元組放在前面,高位元組放在後面。 要明白,後面的記憶體地址比前面大1,也就是低位元組放在地址小的空間,高位元組放在地址大的空間。綜上所述:無論對於bitset還是計算機機器字的記憶體儲存方式(其實是同一個),只要記住低階對應於記憶體地址較小小的空間,高階對應於記憶體地址較大的空間。(低対低,高對高,一一對應)。

知道了以上這些,對於bitset的儲存方式,就很容易理解了。例:

	//1. 用unsigned 值初始化
	bitset<16> bitvec1(0xfffa);
	bitset<32> bitvec2(0xffff);
	cout<<"bitvec1:"<<bitvec1<<endl;
	cout<<"bitvec2:"<<bitvec2<<endl;
輸出:bitvec1:1111111111111010
           bitvec2:00000000000000001111111111111010

這時奇怪的事發生了,輸出並不是期待的順序,而是相反的。這裡還要說的是,bitset實現的<<操作符輸出時,將會從bitset的高階-->低階輸出(更自然)。因此若用for迴圈從0開始輸出就會是實際儲存的順序了。

	cout<<"bitvec1(RAW):"<<bitvec1<<endl;
	cout<<"bitvec1(FOR):";
    for(size_t bs1 = 0;bs1!=bitvec1.size();bs1++)
	{
		cout<<bitvec1[bs1];
	}
	cout<<endl;

	cout<<"bitvec2(RAW):"<<bitvec2<<endl;
	cout<<"bitvec2(FOR):";
    for(size_t bs1 = 0;bs1!=bitvec2.size();bs1++)
	{
		cout<<bitvec2[bs1];
	}
	cout<<endl;

輸出為:bitvec1(RAW):1111111111111010
               bitvec1(FOR):0101111111111111
               bitvec2(RAW):00000000000000001111111111111010
               bitvec2(FOR):01011111111111110000000000000000


      (2). 用string物件初始化bitset物件

當用string物件初始化bitset物件時,string物件直接表示為位模式。從string物件讀入位集的順序是從右到左。

	//2. 用string物件初始化
	string strval("1100");
	bitset<8> bitvec4(strval);
	cout<<"bitvec4(RAW):"<<bitvec4<<endl;

	cout<<"bitvec4(FOR):";
	for(size_t bs = 0;bs!=bitvec4.size();bs++)
	{
		cout<<bitvec4[bs];
	}
輸出:bitvec4(RAW):00001100

          bitvec4(FOR):00110000

上述string物件strval可看成字元陣列{'1', '1', '0', '0'}.

從上可以看出,string物件與bitset物件之間是反向轉化的:string物件的最右邊字元(既下標最大的那個字元)用來初始化bitset物件的低階位(即下標為0的位)。這是與用unsigned值初始化bitset物件不同的。即不是遵從低階高階一一對應的。

   擷取子串作為初始值。

	string str("1111111000000011001101");
	bitset<32> bitvec5(str,5,4);
	bitset<32> bitvec6(str,str.size()-4);
	cout<<"bitvec5:"<<bitvec5<<endl;
	cout<<"bitvec6:"<<bitvec6<<endl;

輸出:bitvec5:00000000000000000000000000001100
         bitvec6:00000000000000000000000000001101

bitvec5用str[5]開始的4個字元子串來初始化。

如果省略第3個引數,則取從開始位置一直到string物件末尾的所有字元,bitvec6用str末尾的4位來初始化。

2. bitset 物件上的操作

       (1). 測試整個bitset物件

	bool is_set = bitvec6.any();	//是否存在置為1 的位
	bool is_not_set = bitvec6.none();	//是否不存在置為1的數

	size_t bits_set = bitvec6.count();	//置為1的數
	cout<<"bits_set: "<<bits_set<<endl;

	size_t sz = bitvec6.size();	//返回bitset物件中對應的二進位制位的個數
	cout<<"bits_size: "<<sz<<endl;
        (2). 訪問bitset 物件的位

   可以用下標操作來讀寫某個索引的二進位制位。

	//訪問bitset物件中的位
	for(int index = 0;index != bitvec6.size(); index++)
	{
		bitvec6[index] = 1;
	}
	//還可呼叫set,reset等操作
	for(int index = 0;index != bitvec6.size();index++)
	{
		bitvec6.set(index);
	}
	//測試
	if(bitvec6.test(3))
	{
	}
	//等價於 
	if(bitvec6[3])
	{
	}
      (3). 對整個bitset物件進行設定
	bitvec5.set();	//設定所有
	bitvec5.reset();   //重置所有
    //取反
	bitvec5.flip(2);  //對某位取反
	bitvec5[2].flip();
	bitvec5.flip(); //對所有位取反
     (4). 獲取bitset 物件的值

to_long 操作返回一個unsigned long 值,該值與bitset的位模式儲存值相同。僅當bitset 型別的長度小於或等於unsigned long 的長度,才可用to_long操作:

	bitset<132> bitvec7(124);
	cout<<"bitvec7: "<<bitvec7<<endl;
	unsigned long ulong = bitvec7.to_ullong();
	cout<<ulong<<endl;
 如果bitset物件包含的二進位制位數超過 unsigned long 的長度,將會產生執行時異常。

   (5) .使用位操作符

bitset 也支援內建的位操作符,這些操作符只適用於整型運算元。

	cout<<"bitvec7: "<<(bitvec7&=0xf)<<endl;