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的儲存方式,就很容易理解了。例:
輸出:bitvec1:1111111111111010//1. 用unsigned 值初始化 bitset<16> bitvec1(0xfffa); bitset<32> bitvec2(0xffff); cout<<"bitvec1:"<<bitvec1<<endl; cout<<"bitvec2:"<<bitvec2<<endl;
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):00001100bitvec4(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
如果省略第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;