Team LiB
Previous Section Next Section

3.5. Library bitset Type

3.5. 标准库 bitset 

Some programs deal with ordered collections of bits. Each bit can contain either a 0 (off) or a 1 (on) value. Using bits is a compact way to keep yes/no information (sometimes called flags) about a set of items or conditions. The standard library makes it easy to deal with bits through the bitset class. To use a bitset we must include its associated header file. In our examples, we also assume an appropriate using declaration for std::bitset is made:

有些程序要处理二进制位的有序集,每个位可能包含 0(关)1(开)值。位是用来保存一组项或条件的 yes/no 信息(有时也称标志)的简洁方法。标准库提供的 bitset 类简化了位集的处理。要使用 bitset 类就必须包含相关的头文件。在本书提供的例子中,假设都使用 std::bitset 的 using 声明:

     #include <bitset>
     using std::bitset;

3.5.1. Defining and Initializing bitsets

3.5.1. bitset 对象的定义和初始化

Table 3.6 lists the constructors for bitset. Like vector, the bitset class is a class template. Unlike vector, objects of type bitset differ by size rather than by type. When we define a bitset, we say how many bits the bitset will contain, which we do by specifying the size between a pair of angle brackets.

表 3.6 列出了 bitset 的构造函数。类似于 vectorbitset 类是一种类模板;而与 vector 不一样的是 bitset 类型对象的区别仅在其长度而不在其类型。在定义 bitset 时,要明确 bitset 含有多少位,须在尖括号内给出它的长度值:

Table 3.6. Ways to Initialize a bitset
表 3.6. 初始化 bitset 对象的方法

bitset<n> b;

b has n bits, each bit is 0

b 有 n 位,每位都 0

bitset<n> b(u);

b is a copy of the unsigned long value u

b 是 unsigned long 型 u 的一个副本

bitset<n> b(s);

b is a copy of the bits contained in string s

b 是 string 对象 s 中含有的位串的副本

bitset<n> b(s, pos, n);

b is a copy of the bits in n characters from s starting from position pos

b 是 s 中从位置 pos 开始的&nbps;n 个位的副本。


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

The size must be a constant expression (Section 2.7, p. 62). It might be defined, as we did here, using an integral literal constant or using a const object of integral type that is initialized from a constant.

给出的长度值必须是常量表达式(2.7 节)。正如这里给出的,长度值值必须定义为整型字面值常量或是已用常量值初始化的整型的 const 对象。

This statement defines bitvec as a bitset that holds 32 bits. Just as with the elements of a vector, the bits in a bitset are not named. Instead, we refer to them positionally. The bits are numbered starting at 0. Thus, bitvec has bits numbered 0 through 31. The bits starting at 0 are referred to as the low-order bits, and those ending at 31 are referred to as high-order bits.

这条语句把 bitvec 定义为含有 32 个位的 bitset 对象。和 vector 的元素一样,bitset 中的位是没有命名的,程序员只能按位置来访问。位集合的位置编号从 0 开始,因此,bitvec 的位序是从 0 到 31。以 0 位开始的位串是低阶位(low-order),以 31 位结束的位串是高阶位(high-order)。

Initializing a bitset from an unsigned Value
用 unsigned 值初始化 bitset 对象

When we use an unsigned long value as an initializer for a bitset, that value is treated as a bit pattern. The bits in the bitset are a copy of that pattern. If the size of the bitset is greater than the number of bits in an unsigned long, then the remaining high-order bits are set to zero. If the size of the bitset is less than that number of bits, then only the low-order bits from the unsigned value are used; the high-order bits beyond the size of the bitset object are discarded.

当用 unsigned long 值作为 bitset 对象的初始值时,该值将转化为二进制的位模式。而 bitset 对象中的位集作为这种位模式的副本。如果 bitset 类型长度大于 unsigned long 值的二进制位数,则其余的高阶位将置为 0;如果 bitset 类型长度小于 unsigned long 值的二进制位数,则只使用 unsigned 值中的低阶位,超过 bistset 类型长度的高阶位将被丢弃。

On a machine with 32-bit unsigned longs, 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.) We can initialize a bitset from 0xffff:

在 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 zero

In all three cases, the bits 0 to 15 are set to one. For bitvec1, the high-order bits in the initializer are discarded; bitvec1 has fewer bits than an unsigned long. bitvec2 is the same size as an unsigned long, so all the bits are used to initialize that object. bitvec3 is larger than an unsigned long, so its high-order bits above 31 are initialized to zero.

上面的三个例子中,0 到 15 位都置为 1。由于 bitvec1 位数少于 unsigned long 的位数,因此 bitvec1 的初始值的高阶被丢弃。bitvec2 和 unsigned long 长度相同,因此所有位正好放置了初始值。bitvec3 长度大于 32,31 位以上的高阶位就被置为 0。

Initializing a bitset from a string
用 string 对象初始化 bitset 对象

When we initialize a bitset from a string, the string represents the bit pattern directly. The bits are read from the string from right to left:

当用 string 对象初始化 bitset 对象时,string 对象直接表示为位模式。从 string 对象读入位集的顺序是从右向左(from right to left)

     string strval("1100");
     bitset<32> bitvec4(strval);

The bit pattern in bitvec4 has bit positions 2 and 3 set to 1, while the remaining bit positions are 0. If the string contains fewer characters than the size of the bitset, the high-order bits are set to zero.

bitvec4 的位模式中第 2 和 3 的位置为 1,其余位置都为 0。如果 string 对象的字符个数小于 bitset 类型的长度,则高阶位置为 0。

The numbering conventions of strings and bitsets are inversely related: The rightmost character in the stringthe one with the highest subscriptis used to initialize the low-order bit in the bitsetthe bit with subscript 0. When initializing a bitset from a string, it is essential to remember this difference.

string 对象和 bitsets 对象之间是反向转化的:string 对象的最右边字符(即下标最大的那个字符)用来初始化 bitset 对象的低阶位(即下标为 0 的位)。当用 string 对象初始化 bitset 对象时,记住这一差别很重要。



We need not use the entire string as the initial value for the bitset. Instead, we can use a substring as the initializer:

不一定要把整个 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 4 characters

Here bitvec5 is initialized by a substring of str starting at str[5] and continuing for four positions. As usual, we start at the rightmost end of this substring when initializing the bitset, meaning that bitvec5 is initialized with bit positions 0 through 3 set to 1100 while its remaining bit positions are set to 0. Leaving off the third parameter says to use characters from the starting position to the end of the string. In this case, the characters starting four from the end of str are used to initialize the lower four bits of bitvec6. The remainder of the bits in bitvec6 are initialized to zero. We can view these initializations as

这里用 str 从 str[5] 开始包含四个字符的子串来初始化 bitvec5。照常,初始化 bitset 对象时总是从子串最右边结尾字符开始的,bitvec5 的从 3 到 0 的二进制位置为 1100 ,其他二进制位都置为 0。如果省略第三个参数则意味着取从开始位置一直到 string 末尾的所有字符。本例中,取出 str 末尾的四位来对 bitvec6 的低四位进行初始化。bitvec6 其余的位初始化为 0。这些初始化过程的图示如下:

3.5.2. Operations on bitsets

3.5.2. bitset 对象上的操作

The bitset operations (Table 3.7) define various operations to test or set one or more bits in the bitset.

多种 bitset 操作(表 3.7)用来测试或设置 bitset 对象中的单个或多个二进制位。

把 b 中所有二进制位都置为 1

Table 3.7. bitset Operations
表 3.7. bitset 操作

b.any()

Is any bit in b on?

b 中是否存在置为 1 的二进制位?

b.none()

Are no bits in b on?

b.count()

Number of bits in b that are on

b 中不存在置为 1 的二进制位吗?

b.size()

Number of bits in b

b 中置为 1 的二进制位的个数

b[pos]

Access bit in b at position pos

访问 b 中在 pos 处二进制位

b.test(pos)

Is bit in b in position pos on?

b 中在 pos 处的二进制位置为 1

b.set()

Turn on all bits in b

b.set(pos)

Turn on the bit in b at position pos

把 b 中在 pos 处的二进制位置为 1

b.reset()

Turn off all bits in b

把 b 中所有二进制位都置为 0

b.reset(pos)

Turn off the bit in b at position pos

把 b 中在 pos 处的二进制位置为 0

b.flip()

Change the state of each bit in b

把 b 中所有二进制位逐位取反

b.flip(pos)

Reverse value of the bit in b in position pos

把 b 中在 pos 处的二进制位取反

b.to_ulong()

Returns an unsigned long with the same bits as in b

用 b 中同样的二进制位返回一个 unsigned long 值

os << b

Prints the bits in b to the stream os

把 b 中的位集输出到 os 流


Testing the Entire bitset
测试整个 bitset 对象

The any operation returns true if one or more bits of the bitset object are turned onthat is, are equal to 1. Conversely, the operation none returns true if all the bits of the object are set to zero.

如果 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

If we need to know how many bits are set, we can use the count operation, which returns the number of bits that are set:

如果需要知道置为 1 的二进制位的个数,可以使用 count 操作,该操作返回置为 1 的二进制位的个数:

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

The return type of the count operation is a library type named size_t. The size_t type is defined in the cstddef header, which is the C++ version of the stddef.h header from the C library. It is a machine-specific unsigned type that is guaranteed to be large enough to hold the size of an object in memory.

count 操作的返回类型是标准库中命名为 size_t 类型。size_t 类型定义在 cstddef 头文件中,该文件是 C 标准库的头文件 stddef.h 的 C++ 版本。它是一个与机器相关的 unsigned 类型,其大小足以保证存储内在中对象的大小。

The size operation, like the one in vector and string, returns the total number of bits in the bitset. The value returned has type size_t:

与 vector 和 string 中的 size 操作一样,bitset 的 size 操作返回 bitset 对象中二进制位的个数,返回值的类型是 size_t:

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

Accessing the Bits in a bitset
访问 bitset 对象中的位

The subscript operator lets us read or write the bit at the indexed position. As such, we can use it to test the value of a given bit or to set that value:

可以用下标操作符来读或写某个索引位置的二进制位,同样地,也可以用下标操作符测试给定二进制位的值或设置某个二进制们的值:

     // assign 1 to even numbered bits
     for (int index = 0; index != 32; index += 2)
                 bitvec[index] = 1;

This loop turns on the even-numbered bits of bitvec.

上面的循环把 bitvec 中的偶数下标的位都置为 1。

As with the subscript operator, we can use the set, test, and reset operations to test or set a given bit value:

除了用下标操作符,还可以用 set;、test 和 reset 操作来测试或设置给定二进制位的值:

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

To test whether a bit is on, we can use the test operation or test the value returned from the subscript operator:

为了测试某个二进制位是否为 1,可以用 test 操作或者测试下标操作符的返回值:

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

The result of testing the value returned from a subscript is true if the bit is 1 or false if the bit is 0.

如果下标操作符测试的二进制位为 1,则返回的测试值的结果为 true,否则返回 false

Setting the Entire bitset
对整个 bitset 对象进行设置

The set and reset operations can also be used to turn on or turn off the entire bitset object, respectively:

set 和 reset 操作分别用来对整个 bitset 对象的所有二进制位全置 1 和全置 0:

     bitvec.reset(); // set all the bits to 0.
     bitvec.set();   // set all the bits to 1

The flip operation reverses the value of an individual bit or the entire bitset:

flip 操作可以对 bitset 对象的所有位或个别位取反:

     bitvec.flip(0);   // reverses value of first bit
     bitvec[0].flip(); // also reverses the first bit
     bitvec.flip();    // reverses value of all bits

Retrieving the Value of a bitset
获取 bitset 对象的值

The to_ulong operation returns an unsigned long that holds the same bit pattern as the bitset object. We can use this operation only if the size of the bitset is less than or equal to the size of an unsigned long:

to_ulong 操作返回一个 unsigned long 值,该值与 bitset 对象的位模式存储值相同。仅当 bitset 类型的长度小于或等于 unsigned long 的长度时,才可以使用 to_ulong 操作:

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

The to_ulong operation is intended to be used when we need to pass a bitset to a C or pre-Standard C++ program. If the bitset contains more bits than the size of an unsigned long, a run-time exception is signaled. We'll introduce exceptions in Section 6.13 (p. 215) and look at them in more detail in Section 17.1 (p. 688).

to_ulong 操作主要用于把 bitset 对象转到 C 风格或标准 C++ 之前风格的程序上。如果 bitset 对象包含的二进制位数超过 unsigned long 长度,将会产生运行时异常。本书将在 6.13 节介绍异常(exception),并在 17.1 节中详细地讨论它。

Printing the Bits
输出二进制位

We can use the output operator to print the bit pattern in a bitset object:

可以用输出操作符输出 bitset 对象中的位模式:

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

will print

输出结果为:

     bitvec2: 00000000000000001111111111111111

Using the Bitwise Operators
使用位操作符

The bitset class also supports the built-in bitwise operators. As defined by the language, these operators apply to integral operands. They perform operations similar to the bitset operations described in this section. Section 5.3 (p. 154) describes these operators.

bitset 类也支持内置的位操作符。C++ 定义的这些操作符都只适用于整型操作数,它们所提供的操作类似于本节所介绍的 bitset 操作。5.3 节将介绍这些操作符。

Exercises Section 3.5.2

Exercise 3.23:

Explain the bit pattern each of the following bitset objects contains:

解释下面每个 bitset 对象包含的位模式:

     (a) bitset<64> bitvec(32);
     (b) bitset<32> bv(1010101);
     (c) string bstr; cin >> bstr; bitset<8>bv(bstr);

Exercise 3.24:

Consider the sequence 1,2,3,5,8,13,21. Initialize a bitset<32> object that has a one bit in each position corresponding to a number in this sequence. Alternatively, given an empty bitset, write a small program to turn on each of the appropriate bits.

考虑这样的序列 1,2,3,5,8,13,21,并初始化一个将该序列数字所对应的位置置为 1 的 bitset<32> 对象。然后换个方法,给定一个空的 bitset,编写一小段程序把相应的数位设置为 1。


    Team LiB
    Previous Section Next Section