《C++Primer》第三章-標準庫類型-學習筆記(2)-bitset

《C++Primer》第三章-標準庫類型-學習筆記(2)

日誌:
1,2020-02-29 筆者提交文章的初版V1.0

作者按:
最近在學習C++ primer,初步打算把所學的記錄下來。

傳送門/推廣
《C++Primer》第二章-變量和基本類型-學習筆記(1)
《C++Primer》第二章-變量和基本類型-學習筆記(2)
《C++Primer》第二章-變量和基本類型-學習筆記(3)
上一篇
《C++Primer》第三章-標準庫類型-學習筆記(1)

標準庫 bitset

標準庫提供的 bitset 類簡化了位集的處理。.有些程序要處理二進制位的有序集,每個位可能包含 0(關)1(開)值。位是用來保存一組項或條件的 yes/no 信息(有時也稱標誌)的簡潔方法。

bitset 對象的定義和初始化

bitset 的構造函數類似於 vector,bitset 類是一種類模板;而與 vector 不一樣的是 bitset 類型對象的區別僅在其長度而不在其類型。在定義 bitset 時,要明確 bitset 含有多少位,須在尖括號內給出它的長度值:

bitset<32> bitvec; // 32 bits, all zero

給出的長度值必須是常量表達式[2][3]正如這裏給出的,長度值值必須定義爲整型字面值常量或是已用常量值初始化的整型的 const 對象。
這條語句把 bitvec 定義爲含有 32 個位的 bitset 對象。和 vector 的元素一樣,bitset 中的位是沒有命名的,程序員只能按位置來訪問。位集合的位置編號從 0 開始,因此,bitvec 的位序是從 0 到 31。以 0 位開始的位串是低階位(low-order),以 31 位結束的位串是高階位(high-order)

構造函數 效果
bitset< n > b; b 有 n 位,每位都 0
bitset< n > b(u); b 是 unsigned long 型 u 的一個副本
bitset< n > b(s); b 是 string 對象 s 中含有的位串的副本
bitset< n > b(s, pos, n); b 是 s 中從位置 pos 開始的 n 個位的副本。
表1. bitset 的構造函數

用unsigned 值初始化 bitset 對象

當用 unsigned long 值作爲 bitset 對象的初始值時,該值將轉化爲二進制的位模式。而 bitset 對象中的位集作爲這種位模式的副本。

  • 如果 bitset 類型長度大於 unsigned long 值的二進制位數,則其餘的高階位將置爲 0;
  • 如果 bitset 類型長度小於 unsigned long 值的二進制位數,則只使用 unsigned 值中的低階位,超過 bistset 類型長度的高階位將被丟棄。

在 32 位 unsigned long 的機器上,十六進制值 0xffff 表示爲二進制位就是十六個 1 和十六個 0(每個 0xf 可表示爲 1111)。可以用 0xffff 初始化 bitset 對象:

// bitvec1 is smaller than the initializer
bitset<16> bitvec1(0xffff); // bits 0 ... 15 are set to 1
// bitvec2 same size as initializer
bitset<32> bitvec2(0xffff); // bits 0 ... 15 are set to 1;
16 ... 31 are 0
// on a 32-bit machine, bits 0 to 31 initialized from 0xffff
bitset<128> bitvec3(0xffff); // bits 32 through 127 initialized to 0

用string 對象初始化 bitset 對象

當用 string 對象初始化 bitset 對象時,string 對象直接表示爲位模式。
從 string 對象讀入位集的順序是從右向左(from right to left):

string strval("1100");
bitset<32> bitvec4(strval); //初始化爲00000000000000000000000000001100
//bitvec4 的位模式中第 2 和 3 的位置爲 1,其餘位置都爲 0。如果 string 對
//象的字符個數小於 bitset 類型的長度,則高階位置爲 0。

string 對象和 bitsets 對象之間是反向轉化的:string 對象的最右邊字符(即下標最大的那個字符)用來初始化 bitset 對象的低階位(即下標爲 0 的位)。當用 string 對象初始化 bitset 對象時,記住這一差別很重要。
不一定要把整個 string 對象都作爲 bitset 對象的初始值。相反,可以只用某個子串作爲初始值:

string str("1111111000000011001101");
bitset<32> bitvec5(str, 5, 4); // 4 bits starting at str[5], 1100
bitset<32> bitvec6(str, str.size() - 4); // use last 4characters,省略第三個參數,意思是從右邊複製到str.size() - 4位,這裏是1101

這裏用 str 從 str[5] 開始包含四個字符的子串來初始化 bitvec5。照常,初始化 bitset 對象時總是從子串最右邊結尾字符開始的,bitvec5 的從 3 到 0 的二進制位置爲 1100 ,其他二進制位都置爲 0。如果省略第三個參數則意味着取從開始位置一直到 string 末尾的所有字符。本例中,取出 str 末尾的四位來對 bitvec6 的低四位進行初始化。bitvec6 其餘的位初始化爲 0。
在這裏插入圖片描述

bitset 對象上的操作

多種 bitset 操作用來測試或設置 bitset 對象中的單個或多個二進制位。

操作函數 效果
b.any() b 中是否存在置爲 1 的二進制位? 返回值bool
b.none() b 中不存在置爲 1 的二進制位嗎?返回值bool
b.count() b 中置爲 1 的二進制位的個數。返回類型是標準庫中命名爲 size_t 類型
b.size() b 中二進制位的個數
b[pos] 訪問 b 中在 pos 處二進制位
b.test(pos) b 中在 pos 處的二進制位置爲 1 麼?
b.set() 把 b 中所有二進制位都置爲 1
b.set(pos) 把 b 中在 pos 處的二進制位置爲 1
b.reset() 把 b 中所有二進制位都置爲 0
b.reset(pos) 把 b 中在 pos 處的二進制位置爲 0
b.flip() 把 b 中所有二進制位逐位取反
b.flip(pos) 把 b 中在 pos 處的二進制位取反
b.to_ulong() 用 b 中同樣的二進制位返回一個 unsigned long 值
os << b 把 b 中的位集輸出到 os 流

測試整個 bitset 對象

如果 bitset 對象中有一個或幾個二進制位置爲 1,則 any 操作返回 true,也就是說,其返回值等於 1;相反,如果 bitset 對象中二進制位全爲 0,則 none 操作返回 true。

bitset<32> bitvec; // 32 bits, all zero
bool is_set = bitvec.any(); // false, all bits are zero
bool is_not_set = bitvec.none(); // true, all bits are zero

如果需要知道置爲 1 的二進制位的個數,可以使用 count 操作,該操作返回置爲 1 的二進制位的個數:

size_t bits_set = bitvec.count(); // returns number of bits that are on

count 操作的返回類型是標準庫中命名爲 size_t 類型。size_t 類型定義在 cstddef 頭文件中,該文件是 C 標準庫的頭文件 stddef.h 的 C++ 版本。它是一個與機器相關的 unsigned 類型,其大小足以保證存儲內在中對象的大小。

size_t bits_set = bitvec.count(); // returns number of bits that are on

與 vector 和 string 中的 size 操作一樣,bitset 的 size 操作返回 bitset 對象中二進制位的個數,返回值的類型是 size_t::

size_t sz = bitvec.size(); // returns 32

訪問 bitset 對象中的位

可以用下標操作符來讀或寫某個索引位置的二進制位,同樣地,也可以用下標操作符測試給定二進制位的值或設置某個二進制們的值

// assign 1 to even numbered bits 把 bitvec 中的偶數下標的位都置爲 1。
for (int index = 0; index != 32; index += 2)
	bitvec[index] = 1;

用 set;、test 和 reset 操作來測試或設置給定二進制位的值:

// equivalent loop using set operation
for (int index = 0; index != 32; index += 2)
	bitvec.set(index);

爲了測試某個二進制位是否爲 1,可以用 test 操作或者測試下標操作符的返回值:

if (bitvec.test(i))  // bitvec[i] is on
// equivalent test using subscript
if (bitvec[i]) 		 // bitvec[i] is on

如果下標操作符測試的二進制位爲 1,則返回的測試值的結果爲 true,否則返回 false。

對整個bitset 對象進行設置

flip 操作可以對 bitset 對象的所有位或個別位取反:

bitvec.flip(0); // reverses value of first bit  取反第0位
bitvec[0].flip(); // also reverses the first bit  這個很值得記憶
bitvec.flip(); // reverses value of all bits

獲取 bitset 對象的值

to_ulong 操作返回一個 unsigned long 值,該值與 bitset 對象的位模式存儲值相同。僅當 bitset 類型的長度小於或等於 unsigned long 的長度時,纔可以使用 to_ulong 操作:

unsigned long ulong = bitvec3.to_ulong();
cout << "ulong = " << ulong << endl;

to_ulong 操作主要用於把 bitset 對象轉到 C 風格或標準 C++ 之前風格的程序上。如果 bitset 對象包含的二進制位數超過 unsigned long 長度,將會產生運行時異常。

輸出二進制位

可以用輸出操作符輸出 bitset 對象中的位模式:

bitset<32> bitvec2(0xffff); // bits 0 ... 15 are set to 1; 16 ...31 are 0
cout << "bitvec2: " << bitvec2 << endl;

輸出結果爲:

bitvec2: 00000000000000001111111111111111

使用位操作符

bitset 類也支持內置的位操作符。C++ 定義的這些操作符都只適用於整型操作數,它們所提供的操作類似於本節所介紹的 bitset 操作。

參考資料

【1】C++ Primer 中文版(第四版·特別版)
【2】《C++Primer》第二章-變量和基本類型-學習筆記(3)

註解

【3】常量表達式(const experssion):是指值不會改變,且在編譯過程就能得到計算結果的表達式。字面量是常量表達式,一個通過常量表達式自我初始化的 const對象也是常量表達式。

本文許可證

本文遵循 CC BY-NC-SA 4.0(署名 - 非商業性使用 - 相同方式共享) 協議,轉載請註明出處,不得用於商業目的。
CC BY-NC-SA 4.0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章