Converting Bitsets
The bitset class provides two operations for these jobs, to_string() and to_ullong().
Predicting a Bitset's Printed Form
A bitset stores a fixed run of bits. Often the same bits are needed in another form: sometimes a program must show them as text, and sometimes it must hand the stored value back as a plain integer. The bitset class provides two operations for these jobs, to_string() and to_ullong(). Each one is designed as the reverse of a bitset constructor, so the idea of a round trip runs through this whole topic.
What do you think happens?
Given a bitset of 8 bits holding the value 5, what does to_string() print?
Reveal answer
00000101
The bitset is 8 bits wide, so the text has exactly 8 characters. The value 5 is 101 in binary, and the leading zeros fill the remaining positions on the left. The string is written with the most significant bit leftmost.
Copying an Integer into a Bitset
The source example is a small function. It takes an int, copies it into a bitset sized to hold the whole int, and writes the bits out with to_string(). The function has two lines that matter, and they do different jobs. One line does the copying, which happens when the bitset is constructed from the int. The other line does the printing, which happens when cout writes the string that to_string() returns. Keep these two jobs separate in your mind as you trace the code.
Reading Characters with to_string()
In the function, the call b.to_string() produces the characters that cout then writes. The string contains only the characters 1 and 0. Because it is text, it is printed exactly as it is. It is not converted into a number along the way. The source describes the result as the bits written from left to right, which is the same direction you read a number written on paper.
The ordering follows place-value notation. The first character on the left is the most significant bit, which is the bit with the highest value. Reading left to right moves from the highest-value bit down to the lowest-value bit. The rightmost character is the least significant bit.
00000000000000000000000000000101- std::bitset<8 *
sizeof(int)> sets the width to the number of bits in an int, assuming a byte is 8 bits - The constructor copies the int value n into the bitset b
b.to_string()returns the bits as text, most significant bit first- cout writes that text unchanged
Why Leading Zeros Appear
The width of a bitset comes from its declaration, not from the value it holds. In the function above the width is 8 * sizeof(int). Because of this, the printed string always has that many characters, even when the value is small. The number of characters depends on how large int is in the environment where the code runs. The source comment states the assumption that a byte is 8 bits.
Tracing bitset<4> holding 6
Trace the output of this code: std::bitset<4> b(6); std::cout << b.to_string();
- 1Declare the width
The bitset has 4 bits, so
to_string()will return exactly 4 characters. - 2Copy the value
The constructor stores the value 6 in the bitset.
- 3Write the bits from the highest position
The value 6 is 110 in binary. Padded to 4 bits, the leftmost bit is 0, giving 0110.
- 4Print the text
cout writes the 4 characters exactly as they are.
0110
Returning to an Integer with to_ullong()
Where to_string() gives back text, to_ullong() gives back a numeric value. It is the inverse of the bitset constructor that takes an unsigned long long integer. The constructor moves a number into the bitset, and to_ullong() reads the bitset's value back out as a number. The output is an integer, not a string of characters.
The following illustration is a small example of our own, not one from the source. It builds a bitset from a string of bits and then reads the value back as an integer. The string constructor and to_string() form one pair, and the integer constructor and to_ullong() form the other.
10
00001010- The string constructor reads the characters 0 and 1 into the bitset
to_ullong()returns the stored value as an unsigned long long, here 10to_string()returns the same bits as text, reversing the string constructor
Mistakes Beginners Make with Printed Bitsets
Common mistake Expecting to_string() to print a decimal number
What it looks likebitset<8> b(5); cout << b.to_string(); prints 00000101, not 5Why it failsto_string()returns the bits as text made of 1 and 0 characters.Do this insteadUse to_ullong() when you need the value as a number, or read the printed bits as binary.
Common mistake Reading the string from right to left
What it looks likeTreating 00000110 as if its first character were the least significant bit
Why it failsThe string places the most significant bit on the left, so the rightmost character is the least significant bit.
Do this insteadRead left to right from the highest-value bit down to the lowest-value bit.
Common mistake Forgetting the leading zeros
What it looks likeExpecting bitset<8> holding 5 to print as 101
Why it failsThe width comes from the declaration, so the output always has that many characters.
Do this insteadCount the declared width first, then pad the value's binary digits with zeros on the left.
Practice Tracing the Round Trip
Before running any code, predict the exact printed output of this program: std::bitset<4> b(9); std::cout << b.to_string(); Then write the result of unsigned long long v = b.to_ullong(); as a value. Compare your prediction with the trace.
Hints
- The width is 4 bits, so the output has 4 characters.
- The value 9 is 1001 in binary.
to_ullong()returns the stored value, which is still 9 because the bitset is 4 bits wide and 9 fits.
Key Takeaways
to_string()is the inverse of the constructor that takes a string. It returns the bitset's binary value as text, with the most significant bit leftmost.to_ullong()is the inverse of the constructor that takes an unsigned long long. It returns the bitset's value as an integer.- The width of a bitset comes from its declaration, such as 8 *
sizeof(int), so the printed output includes leading zeros. - To trace a conversion, follow the value from the constructor into the bitset, then through
to_string()orto_ullong(), and predict the output before comparing it with the real result.