C++ bitset | "Bit Set" Guide

C++ bitset | "Bit Set" Guide

이 글의 핵심

It covers operations on the fixed-size bit set bitset, selection with vector<bool>, and masking/subset practice patterns.

What is bitset?

std::bitset is an STL container representing a fixed-size bitset. It allows efficient storage and manipulation of data bit by bit, and is useful for flags, state management, bit masks, etc.```cpp #include

std::bitset<8> bits; // 8비트

bits.set(0); // 0번 비트 1 bits.set(3); // 3번 비트 1 bits.reset(0); // 0번 비트 0

- Memory efficiency: 1 bit = 1 bool (normal array is 1 byte)
- Bit operations: Intuitive operations such as AND, OR, XOR, NOT, etc.
- Type safety: compile-time size verification
- Convenience: Provides bit manipulation functions```cpp
// ❌ 일반 배열: 8바이트
bool flags[8] = {false};

// ✅ bitset: 1바이트
std::bitset<8> flags;  // 8비트 = 1바이트
```Bit Indexing:```cpp
std::bitset<8> bits{"10101010"};
//                   76543210  (인덱스)

std::cout << bits[0] << '\n';  // 0 (오른쪽)
std::cout << bits[7] << '\n';  // 1 (왼쪽)

// 주의: 문자열과 인덱스 방향이 반대!
```## Default use```cpp
#include <bitset>

// 생성
std::bitset<8> b1;              // 00000000
std::bitset<8> b2{0b10101010};  // 10101010
std::bitset<8> b3{"10101010"};  // 10101010

// 접근
bool bit0 = b2[0];
bool bit7 = b2[7];

// 출력
std::cout << b2 << std::endl;  // 10101010
```## Practical example

### Example 1: Flags```cpp
#include <bitset>

enum Permission {
    Read = 0,
    Write = 1,
    Execute = 2,
    Delete = 3
};

class FilePermissions {
    std::bitset<4> perms;
    
public:
    void grant(Permission p) {
        perms.set(p);
    }
    
    void revoke(Permission p) {
        perms.reset(p);
    }
    
    bool has(Permission p) const {
        return perms[p];
    }
    
    void print() const {
        std::cout << "읽기: " << perms[Read] << std::endl;
        std::cout << "쓰기: " << perms[Write] << std::endl;
        std::cout << "실행: " << perms[Execute] << std::endl;
        std::cout << "삭제: " << perms[Delete] << std::endl;
    }
};

int main() {
    FilePermissions fp;
    fp.grant(Read);
    fp.grant(Write);
    
    if (fp.has(Read)) {
        std::cout << "읽기 가능" << std::endl;
    }
    
    fp.print();
}
```### Example 2: Bitwise operations```cpp
#include <bitset>

int main() {
    std::bitset<8> b1{"11110000"};
    std::bitset<8> b2{"10101010"};
    
    // AND
    auto and_result = b1 & b2;
    std::cout << "AND: " << and_result << std::endl;  // 10100000
    
    // OR
    auto or_result = b1 | b2;
    std::cout << "OR: " << or_result << std::endl;  // 11111010
    
    // XOR
    auto xor_result = b1 ^ b2;
    std::cout << "XOR: " << xor_result << std::endl;  // 01011010
    
    // NOT
    auto not_result = ~b1;
    std::cout << "NOT: " << not_result << std::endl;  // 00001111
}
```### Example 3: Transformation```cpp
#include <bitset>

std::bitset<8> bits{"10101010"};

// 정수로
unsigned long ul = bits.to_ulong();
std::cout << "정수: " << ul << std::endl;  // 170

// 문자열로
std::string str = bits.to_string();
std::cout << "문자열: " << str << std::endl;  // 10101010

// 정수에서
std::bitset<8> bits2{170};
```### Example 4: Count```cpp
#include <bitset>

std::bitset<8> bits{"10101010"};

// 1의 개수
std::cout << "1의 개수: " << bits.count() << std::endl;  // 4

// 크기
std::cout << "크기: " << bits.size() << std::endl;  // 8

// 모두 1?
std::cout << "모두 1: " << bits.all() << std::endl;  // false

// 하나라도 1?
std::cout << "하나라도 1: " << bits.any() << std::endl;  // true

// 모두 0?
std::cout << "모두 0: " << bits.none() << std::endl;  // false
```## Bit operations```cpp
std::bitset<8> bits;

// 설정
bits.set();      // 모두 1
bits.set(3);     // 3번 비트 1
bits.set(3, 0);  // 3번 비트 0

// 리셋
bits.reset();    // 모두 0
bits.reset(3);   // 3번 비트 0

// 플립
bits.flip();     // 모두 반전
bits.flip(3);    // 3번 비트 반전

// 테스트
bool bit3 = bits.test(3);
```## Bit operation basics

A summary of frequently used operations in integers or `bitset` is as follows.

| operations | meaning | Example Intuition |
|------|------|-------|
| AND `&` | Only positions where both are 1 | Extract only specific bits with mask |
| OR (bitwise OR) | If even one is 1, then 1 | Beat On |
| XOR `^` | If they are different, 1 | Toggle, Compare for equality |
| NOT `~` | Everything is reversed | Flip entire mask |
| `<<` / `>>` | Shift left/right | \(2^k\) Movement corresponding to multiplication and division |

`std::bitset` overloads the above operation for the entire bit set, so AND/OR/XOR/NOT can be performed at once without a loop. Unlike integers, operations between bitsets of different sizes must have the same size at compile time.```cpp
std::bitset<8> a{"11001100"};
std::bitset<8> b{"10101010"};
std::bitset<8> low4 = a & std::bitset<8>{"00001111"};  // 하위 4비트만
```## bitset vs vector<bool>

Both aim for bit-wise compression, but their roles are different.

| Item | `std::bitset<N>` | `std::vector<bool>` |
|------|------------------|----------------------|
| size | Compile-time constant N (template argument) | `resize` possible at runtime |
| Save location | Fixed size, usually inside a stack or object | dynamic allocation on heap |
| operations | Rich bit operations such as AND·OR·XOR·NOT and shift | Element-specific approach/focus on some algorithms |
| Standard Guarantee | complete bit set type | Due to the specialization of `vector`, details such as references are difficult |

What to use and when

- If N is fixed in the code (e.g. 64 bits for flags, 32 bits for IPv4 mask), `bitset<N>` is type safe and the operation is clear.
- If the length changes depending on user input or file size, consider alternatives such as `vector<bool>` or `boost::dynamic_bitset` if the bit length is very large.
- Note in the documentation that `vector<bool>` is a “collection of bools” and not theoretically equivalent to the full `vector<T>` (e.g. `std::vector<bool>::reference`).

## Bit masking pattern

Turn on/off/toggle specific bits```cpp
unsigned x = 0b1010;
unsigned mask = 1u << 3;   // 3번 비트
x |= mask;                 // 켜기
x &= ~mask;                // 끄기
x ^= mask;                 // 토글
```In `bitset`, you can do the same thing more readably with `set(pos)`, `reset(pos)`, and `flip(pos)`.

Keep only low-order k bits: `x & ((1u << k) - 1)`  
Extract specific section bits: Combine shift and AND.```cpp
std::bitset<16> v{"1111000011110000"};
auto low8 = (v & std::bitset<16>{"0000000011111111"});  // 개념적으로 하위 8비트
```## Practice: Flag management, permutation, combination

### Flag combination

The pattern of putting multiple options in one integer or `bitset` and passing them as bitwise OR is common in API flags.```cpp
enum class Opt : unsigned { A = 1u << 0, B = 1u << 1, C = 1u << 2 };

unsigned f = static_cast<unsigned>(Opt::A) | static_cast<unsigned>(Opt::C);
bool hasB = (f & static_cast<unsigned>(Opt::B)) != 0;
```Writing option indices directly with `bitset` makes the binary output clearer when debugging.

### Subset enumeration (bit mask)

Any subset of the set with elements \(0..n-1\) can be traversed with a mask from `0` to `2^n - 1`.```cpp
#include <bitset>
#include <iostream>

int main() {
    const int n = 4;
    // n이 크면 (1u << n) 오버플로에 주의 (unsigned 비트 폭 이하로 사용)
    for (unsigned mask = 0; mask < (1u << n); ++mask) {
        std::bitset<n> bs(mask);
        std::cout << bs << '\n';
    }
}
```When \(n\) is large, `2^n` explodes, so use backtracking or next subset optimization (e.g. `submask = (submask - 1) & mask`) as appropriate.

### Relationship between combination and permutation

- Combination: It is natural to use the position where the bit is 1 as the “selected element.”
- Permutation: Since the order is important, bits alone are not enough and are often used together with `next_permutation`, etc. However, the `bitset`/`uint32_t` mask appears frequently in State Compression DP, which sets “use or not” as a bit.

## Performance optimization

- Fixed size·Hot loop: The single operation of `bitset<N>` is good for the compiler to optimize word by word. If N is small, put it on the stack and avoid repeated allocations.
- Count: You can find the number of 1s at once with `count()`. When traversing specific bits, index loops and `test(i)` are standard methods, and when very fast least significant bit traversal is required, integer masks and compiler built-in functions (e.g. GCC `__builtin_ctzll`) are reviewed to suit project policy.
- I/O: `to_string()` iterations can be expensive when printing in bulk. If it is not for debugging, consider handling it with integer bit operations or writing the buffer all at once.
- vector<bool> vs bitset: If you don't really need dynamic sizes, `bitset` is often simpler in layout and easier to optimize.

## Frequently occurring problems

### Problem 1: Size```cpp
// 컴파일 타임 크기
std::bitset<8> bits;

// ❌ 런타임 크기
// int n = 8;
// std::bitset<n> bits;  // 에러

// ✅ 런타임 크기: vector<bool>
std::vector<bool> bits(n);
```### Problem 2: Index```cpp
std::bitset<8> bits{"10101010"};

// 인덱스 0: 오른쪽 비트
std::cout << bits[0] << std::endl;  // 0 (오른쪽)
std::cout << bits[7] << std::endl;  // 1 (왼쪽)
```### Problem 3: Conversion```cpp
std::bitset<64> bits{0xFFFFFFFFFFFFFFFF};

// ❌ 오버플로우
// unsigned long ul = bits.to_ulong();  // 32비트 시스템에서 에러

// ✅ unsigned long long
unsigned long long ull = bits.to_ullong();
```### Problem 4: String```cpp
// 문자열 생성
std::bitset<8> bits{"10101010"};

// ❌ 잘못된 문자
// std::bitset<8> bits2{"102"};  // 예외

// ✅ 유효성 검사
try {
    std::bitset<8> bits3{"10201010"};
} catch (const std::invalid_argument&) {
    std::cout << "유효하지 않은 문자" << std::endl;
}
```## Practice pattern

### Pattern 1: State Machine```cpp
enum class State {
    Idle = 0,
    Running = 1,
    Paused = 2,
    Error = 3
};

class StateMachine {
    std::bitset<4> activeStates_;
    
public:
    void enterState(State s) {
        activeStates_.set(static_cast<int>(s));
    }
    
    void exitState(State s) {
        activeStates_.reset(static_cast<int>(s));
    }
    
    bool isInState(State s) const {
        return activeStates_[static_cast<int>(s)];
    }
    
    bool isIdle() const {
        return activeStates_.none();  // 모든 비트 0
    }
};

// 사용
StateMachine sm;
sm.enterState(State::Running);
if (sm.isInState(State::Running)) {
    std::cout << "실행 중\n";
}
```### Pattern 2: Set operations```cpp
class CharSet {
    std::bitset<256> chars_;  // ASCII 문자 집합
    
public:
    void add(char c) {
        chars_.set(static_cast<unsigned char>(c));
    }
    
    bool contains(char c) const {
        return chars_[static_cast<unsigned char>(c)];
    }
    
    CharSet operator&(const CharSet& other) const {
        CharSet result;
        result.chars_ = chars_ & other.chars_;
        return result;
    }
    
    CharSet operator|(const CharSet& other) const {
        CharSet result;
        result.chars_ = chars_ | other.chars_;
        return result;
    }
    
    size_t size() const {
        return chars_.count();
    }
};

// 사용
CharSet vowels;
vowels.add('a'); vowels.add('e'); vowels.add('i');

CharSet consonants;
consonants.add('b'); consonants.add('c');

auto intersection = vowels & consonants;  // 교집합
auto union_set = vowels | consonants;     // 합집합
```### Pattern 3: Bit field compression```cpp
class CompactData {
    std::bitset<32> flags_;
    
public:
    // 0-7: 타입 (8비트)
    void setType(uint8_t type) {
        for (int i = 0; i < 8; ++i) {
            flags_[i] = (type >> i) & 1;
        }
    }
    
    uint8_t getType() const {
        uint8_t type = 0;
        for (int i = 0; i < 8; ++i) {
            if (flags_[i]) {
                type |= (1 << i);
            }
        }
        return type;
    }
    
    // 8-15: 상태 플래그
    void setFlag(int index, bool value) {
        flags_[8 + index] = value;
    }
    
    bool getFlag(int index) const {
        return flags_[8 + index];
    }
};
```## FAQ

### Q1: What is bitset?

A: An STL container representing a fixed-size set of bits. Data can be efficiently stored and manipulated bit by bit.

### Q2: How is the size of the bitset determined?

A: Fixed as a template argument at compile time. The size cannot be changed at runtime.```cpp
std::bitset<8> bits;  // 8비트 고정
```### Q3: What bit operations are supported?

A: Supports AND(`&`), OR(`|`), XOR(`^`), NOT(`~`), left shift (`<<`), and right shift (`>>`).```cpp
std::bitset<8> b1{"11110000"};
std::bitset<8> b2{"10101010"};

auto result = b1 & b2;  // AND
```### Q4: Can I convert it to integer or string?

A: It is possible. Use `to_ullong()`, `to_ullong()`, and `to_string()`.```cpp
std::bitset<8> bits{"10101010"};
unsigned long ul = bits.to_ulong();
std::string str = bits.to_string();
```### Q5: What is the difference from vector<bool>?

A: 
- bitset: fixed size, determined at compile time.
- vector<bool>: Dynamic size, changeable at runtime.```cpp
std::bitset<8> bits;  // 고정
std::vector<bool> vec(8);  // 동적
vec.resize(16);  // OK
```### Q6: What is the memory size of bitset?

A: Number of bits divided by 8 (in bytes). For example, `bitset<8>` is 1 byte, `bitset<32>` is 4 bytes.

### Q7: What is the bit index direction?

A: Index 0 is the right bit.```cpp
std::bitset<8> bits{"10101010"};
//                   76543210  (인덱스)
bits[0];  // 0 (오른쪽)
bits[7];  // 1 (왼쪽)
```### Q8: What are bitset learning resources?

A: 
- "C++ Primer" by Lippman, Lajoie, Moo
- "Effective STL" by Scott Meyers
- [cppreference.com - std::bitset](https://en.cppreference.com/w/cpp/utility/bitset)

Related article: [Bit Manipulation](/blog/cpp-bit-manipulation/), Bit Fields.

One-line summary: `std::bitset` is a fixed-size bit set that is memory efficient and allows for intuitive bitwise operations.

---

## Good article to read together (internal link)

Here's another article related to this topic.

- [C++ Algorithm Set | “Set Algorithm” Guide](/blog/cpp-algorithm-set/)
- [C++ Custom Allocator | “Custom Allocator” Guide](/blog/cpp-custom-allocator/)
- [C++ function object | "Functor" complete guide](/blog/cpp-function-objects/)

## Practical tips

These are tips that can be applied right away in practice.

### Debugging tips
- If you run into a problem, check the compiler warnings first.
- Reproduce the problem with a simple test case

### Performance Tips
- Don't optimize without profiling
- Set measurable indicators first

### Code review tips
- Check in advance for areas that are frequently pointed out in code reviews.
- Follow your team's coding conventions

---
## Practical checklist

This is what you need to check when applying this concept in practice.

### Before writing code
- [ ] Is this technique the best way to solve the current problem?
- [ ] Can team members understand and maintain this code?
- [ ] Does it meet the performance requirements?

### Writing code
- [ ] Have you resolved all compiler warnings?
- [ ] Have you considered edge cases?
- [ ] Is error handling appropriate?

### When reviewing code
- [ ] Is the intent of the code clear?
- [ ] Are there enough test cases?
- [ ] Is it documented?

Use this checklist to reduce mistakes and improve code quality.

---

## Keywords covered in this article (related search terms)

This article will be helpful if you search for C++, bitset, bit, flags, STL, etc.

---

## Related articles

- [C++ Algorithm Copy | ](/blog/cpp-algorithm-copy/)
- [C++ Algorithm Count | ](/blog/cpp-algorithm-count/)
- [C++ Algorithm Generate | ](/blog/cpp-algorithm-generate/)
- [C++ Algorithm | ](/blog/cpp-algorithm-guide/)
- [C++ Algorithm Heap | ](/blog/cpp-algorithm-heap/)