Concepts / Bitset Operations and Access

Bitset Operations and Access

A bitset is a fixed-size collection of bits.

  • Programming

Why a Bitset Needs Starting Values

A bitset is a fixed-size collection of bits. Before you can use one, you need to give it starting values, and C++ offers more than one way to do that. The source material for this lesson states that a bitset can be initialized with an integer or a string. Both forms use the same brace-based declaration style, so the main thing to learn is which kind of value goes inside the braces and what that value means for the bits that end up stored.

What do you think happens?

Before reading on: if you declare bitset<9> bs1 {"110001111"}; and bitset<9> bs2 {399};, do you think the two bitsets hold the same bits, or different bits?

  • The same bits, because 399 is the decimal value that corresponds to the pattern 110001111

  • Different bits, because one value is a string and the other is a number

Reveal answer
Answer:

The same bits. The integer 399 corresponds to the bit pattern 110001111, which is the same nine-character string.

The quotes decide whether the value is read as text or as a number, but they do not change the bits that result when the text and the number describe the same pattern. The rest of this article explains how each form produces its bits.

The lesson follows a simple rhythm: work out what the code should produce, then trace the mechanism that actually produces the bits. Keep the prediction above in mind, because the next sections show exactly how a string and an integer each become a bit pattern.

Reading the Declaration Syntax

A bitset declaration names its size in angle brackets and gives the initial value in braces. The general pattern is bitset<N> bs {value};, where N is the number of bits and value is the initial value you supply. The angle-bracket part controls how many bits the bitset has. The variable name, here bs, is the name you use to refer to the bitset later. The brace-enclosed value controls the starting bits.

The size N is part of the type, so bitset<9> and bitset<8> are different types. A bitset declared with N = 9 always has exactly nine bits, whatever value you pass in. The value inside the braces decides which starting bits those nine positions receive. The source material notes that a bitset can be initialized with different constructors, and that the kind of argument you choose decides which constructor is used.

cpp
bitsetthe bit container type<N>number of bits, part of thetypebsname used to refer to it{value}starting bits, chosen byargument type
What each part of the declaration controls: the template argument sets the size, the name refers to the object, and the brace-enclosed value sets the starting bits.

Tracing a String Initialization

When the value inside the braces is a string literal, the bitset is built from the characters of that string. The string is enclosed in double quotes, which marks it as text rather than a number. In the source example, bitset<9> bs1 {"110001111"}; passes a nine-character string made of 0 and 1 characters. Nine characters fill nine bits, so every character has a bit position to land in.

bit 81 (leftmost character)bit 71bit 60bit 50bit 40bit 31bit 21bit 11bit 01 (rightmost character)
Each character of the string occupies one bit position. Bit 0 is the rightmost position, so the rightmost character of the string sits at index 0 and the leftmost character sits at index 8.
Worked example

Reading bs1 position by position

Given bitset<9> bs1 {"110001111"};, which bit holds the rightmost character, and what value does it have?

  1. 1
    Identify the rightmost character

    The string is 110001111, and its last character is 1.

  2. 2
    Assign it to bit 0

    The rightmost character corresponds to the lowest bit position, bit 0.

  3. 3
    Check the result

    Bit 0 holds 1, which matches the rightmost character of the string.

Result

Bit 0 of bs1 is 1. Reading the string right to left gives bits 0 through 8 as 1, 1, 1, 1, 0, 0, 0, 1, 1.

Tracing an Integer Initialization

When the value inside the braces is an integer, the bitset is built from that number. The source example bitset<9> bs2 {399}; uses an integer literal with no quotes. There is no separate string conversion step in the code, because the value is already a number. The integer form is useful when your starting value is already a number, such as a computed result or a constant.

Formula

The expansion above shows where the bit pattern comes from. The powers 28 and 27 contribute to bits 8 and 7, and the powers 23, 22, 21, and 20 contribute to bits 3, 2, 1, and 0. The remaining bits 6, 5, and 4 are 0. Reading those nine positions from left to right gives 110001111, which is the same pattern as the string in the previous section.

bit 81 (256)bit 71 (128)bit 60bit 50bit 40bit 31 (8)bit 21 (4)bit 11 (2)bit 01 (1)
Each bit position of bs2 holds one binary digit of 399. The labels show the power of two each set bit contributes, which is how the value 399 becomes the pattern 110001111.

Size Mismatch and Padding

The size N is fixed by the angle-bracket value, so the bitset always has exactly that many bits. What happens when the starting value has a different number of bits than N is an important check. If the value has fewer bits than N, the bits that the value does not supply are zero. For example, the four-character string "1011" placed in an eight-bit bitset fills the four low positions, and the four high positions stay 0. If the integer has more significant bits than N can hold, the bits beyond position N minus 1 are not kept, so bitset<8> {399} keeps only the low eight bits of 399.

10114 characters110001111399 in 9 bits000010118 bits, high bits zero10001111low 8 bits of 399bitset<8> bs {"1011"}bitset<8> bs {399}
On the top row, a four-character string is padded with zeros to fill eight bits. On the bottom row, a nine-bit integer pattern is cut down to its low eight bits when the declared size is eight.

Because N is part of the declaration, a mismatch between the value and N is a common source of unexpected bit patterns. When you check an initialization, compare the number of bits the value actually supplies with the N you declared.

Comparing Two Initializations Position by Position

Two differently initialized bitsets hold the same bit pattern when every index has the same value in both. You can check this position by position: write down the bits of each bitset from bit N minus 1 down to bit 0, then compare the two lists. If every position matches, the bitsets hold the same pattern, even though the initial values were written in different forms.

cpp
Output
a and b hold the bit pattern 00001011 at every index
Notes on the code
  • a is built from the string 1011, which is 11 in binary
  • b is built from the integer 11, which is 1011 in binary
  • Both declarations use N = 8, so both have eight positions

What do you think happens?

Given bitset<8> a {"1011"}; and bitset<8> b {11};, do a and b hold identical bits at every index?

  • Yes, at every index

  • No, they differ at some index

Reveal answer
Answer:

Yes, at every index. Both hold 00001011, with bit 0 equal to 1, bit 1 equal to 1, bit 2 equal to 0, bit 3 equal to 1, and bits 4 through 7 equal to 0.

The string 1011 and the integer 11 describe the same binary number, and both declarations use the same size of eight. The argument form changes the constructor used, not the pattern.

Mistakes in Initialization

When two declarations that should match do not, the mismatch points to one of three places: the value you passed, the size you declared, or the constructor form you chose. Check each of these in turn.

  • Common mistake

    Leaving out the quotes around a bit string

    What it looks like
    bitset<9> bs {110001111};
    Why it fails

    Quotes decide whether a value is read as text or as a number. Without quotes, 110001111 is read as a decimal integer, which is a different number from the pattern 110001111 in binary.

    Do this instead

    Write bitset<9> bs {"110001111"}; when you mean the bit string, and write bitset<9> bs {399}; when you mean the number.

  • Common mistake

    Declaring a size that does not match the value

    What it looks like
    bitset<8> bs {399};
    Why it fails

    The integer has more significant bits than the eight positions N can hold, so the high bit that gives 399 its value is not kept.

    Do this instead

    Check that the bits the value needs fit within N, or choose a larger N.

  • Common mistake

    Assuming the string and integer forms always produce the same bits

    What it looks like
    bitset<8> a {"1011"}; bitset<8> b {1011};
    Why it fails

    The second declaration uses the decimal integer 1011, not the binary pattern 1011, so the two bitsets hold different bits.

    Do this instead

    Use the integer 11 when you mean the pattern 1011, or use the string "1011" when you want the literal bits.

  • Common mistake

    Changing the declared size without rechecking the value, so the same brace-enclosed value now produces a different pattern

Practicing Bit Pattern Predictions

EASY

Without running the code, decide whether bitset<8> x {"0110"}; and bitset<8> y {6}; hold the same bits at every index. Write down the bit at index 0 and the bit at index 2 for each bitset, then justify your answer.

Hints
  • Convert the integer 6 to binary first. Which bits does 6 set?
  • The string 0110 has four characters, so the rightmost character sits at index 0.
  • Compare index 0 and index 2 before checking the other positions.
MEDIUM

Declare bitset<9> with the string value that matches bs2 {399}; in the source example, then explain why the declaration with a missing pair of quotes would produce a different bit pattern.

Hints
  • The string value that matches 399 is 110001111.
  • Without quotes, the braces read the digits as a decimal integer, so the value changes.

Key Takeaways

  • A bitset is declared as bitset<N> bs {value};, where N is the number of bits and N is part of the type.
  • A string value in double quotes, such as "110001111", fills the bits from the rightmost character at index 0 upward.
  • An integer value with no quotes, such as 399, produces a bit pattern; here 399 corresponds to 110001111, the same bits as the string form.
  • Two initializations hold the same pattern when every index matches, and mismatches usually come from the value passed, the size declared, or the constructor form chosen.

More concepts starting with B