C++ 비트 조작 최적화 기법
비트 조작은 플래그 관리, 마스킹, 집합 연산, 해시, 압축 데이터 등 다양한 분야에서 조건문이나 나눗셈보다 훨씬 빠른 연산을 제공합니다. C++20의 <bit> 헤더는 이식 가능한 표준 비트 유틸리티를 제공합니다.
1. 기본 비트 연산
섹션 제목: “1. 기본 비트 연산”uint32_t flags = 0;
// 비트 설정flags |= (1u << 3); // 3번 비트 ON
// 비트 해제flags &= ~(1u << 3); // 3번 비트 OFF
// 비트 토글flags ^= (1u << 3); // 3번 비트 반전
// 비트 확인bool is_set = (flags >> 3) & 1u;
// 최하위 비트(LSB) 추출uint32_t lsb = flags & (-flags);
// 최하위 비트 제거flags &= flags - 1;
// 2의 거듭제곱 확인bool is_power_of_2 = n && !(n & (n - 1));2. C++20 <bit> 헤더
섹션 제목: “2. C++20 <bit> 헤더”#include <bit>#include <cstdint>
uint32_t v = 0b1010'0110;
// 1인 비트 개수 (popcount)int ones = std::popcount(v); // 4
// 선행 0 개수int lz = std::countl_zero(v); // 24 (32비트 기준)
// 후행 0 개수 (최하위 SET 비트 위치)int tz = std::countr_zero(v); // 1
// 선행 1 개수int lo = std::countl_one(~v);
// 비트 순환 이동uint32_t rotated = std::rotl(v, 3); // 왼쪽 3칸uint32_t rotr = std::rotr(v, 1); // 오른쪽 1칸
// 2의 거듭제곱으로 올림uint32_t next2 = std::bit_ceil(v); // v보다 크거나 같은 2^n
// 2의 거듭제곱으로 내림uint32_t prev2 = std::bit_floor(v);
// 비트 너비 (log2 + 1)int width = std::bit_width(v); // 8 (0b1010_0110은 8비트 필요)3. 비트마스크 플래그 패턴
섹션 제목: “3. 비트마스크 플래그 패턴”enum class ItemFlags : uint32_t{ None = 0, Stackable = 1 << 0, Equippable= 1 << 1, Quest = 1 << 2, Tradeable = 1 << 3, Enchanted = 1 << 4,};
// 비트 OR/AND/NOT 연산자 활성화inline ItemFlags operator|(ItemFlags a, ItemFlags b){ return static_cast<ItemFlags>(uint32_t(a) | uint32_t(b)); }inline ItemFlags operator&(ItemFlags a, ItemFlags b){ return static_cast<ItemFlags>(uint32_t(a) & uint32_t(b)); }inline bool has(ItemFlags flags, ItemFlags flag){ return (flags & flag) != ItemFlags::None; }
ItemFlags sword = ItemFlags::Equippable | ItemFlags::Enchanted;bool canEquip = has(sword, ItemFlags::Equippable); // true4. std::bitset
섹션 제목: “4. std::bitset”#include <bitset>
std::bitset<64> visited; // 64개 방문 플래그
// 설정/해제/확인visited.set(5);visited.reset(5);bool v = visited.test(5);
// 집합 연산std::bitset<64> a(0xF0F0F0F0ULL);std::bitset<64> b(0xFF00FF00ULL);auto intersection = a & b;auto union_set = a | b;
// 순회: 설정된 비트for (size_t i = 0; i < 64; ++i) if (visited.test(i)) process(i);
// 카운트std::cout << visited.count(); // SET 비트 수5. 비트 트릭 — 실전 최적화
섹션 제목: “5. 비트 트릭 — 실전 최적화”// 2의 거듭제곱으로 정렬된 크기로 올림 (버퍼 크기 계산)size_t next_pow2(size_t n){ return std::bit_ceil(n);}
// XOR 스왑 (임시 변수 없이)void xor_swap(int& a, int& b){ if (&a != &b) { a ^= b; b ^= a; a ^= b; }}
// 바이트 순서 반전 (endian swap)uint32_t bswap(uint32_t v){ return std::byteswap(v); // C++23 // 또는: __builtin_bswap32(v) (GCC/Clang)}
// n번째 SET 비트 위치 찾기int nth_set_bit(uint64_t mask, int n){ while (n--) mask &= mask - 1; // LSB 제거 return std::countr_zero(mask);}6. 게임 개발 활용 — 컴포넌트 시스템
섹션 제목: “6. 게임 개발 활용 — 컴포넌트 시스템”using ComponentMask = uint64_t;
constexpr ComponentMask TRANSFORM = 1ULL << 0;constexpr ComponentMask RIGID_BODY = 1ULL << 1;constexpr ComponentMask RENDERER = 1ULL << 2;constexpr ComponentMask COLLIDER = 1ULL << 3;
// 엔티티가 시스템 조건을 만족하는지 확인bool matches_system(ComponentMask entity, ComponentMask required){ return (entity & required) == required;}
ComponentMask player = TRANSFORM | RIGID_BODY | RENDERER | COLLIDER;ComponentMask physics_required = TRANSFORM | RIGID_BODY;
bool runs_physics = matches_system(player, physics_required); // trueC++20 <bit> 헤더로 popcount, countr_zero, rotl 등 이식 가능한 비트 유틸리티를 사용하세요. 비트마스크 플래그는 enum class로 타입 안전성을 보장하고, ECS 컴포넌트 마스크는 uint64_t 비트 연산으로 O(1) 쿼리를 구현하세요.