CodeNebula
C++20stladvanced

std::countr_zero / std::countr_one (C++20 Addition)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

`countr_zero` counts consecutive zero bits from the least significant bit. `countr_one` counts consecutive one bits from the LSB. The classic "find first set bit" operation.

Real-World Scenario

Find the lowest available slot in a bitmap allocator by counting trailing ones.

Quick Snippet

snippet.cpp
#include <bit>
#include <cstdint>

uint32_t bitmap = 0b00000000'00000000'00000000'00010100;
auto trailing_zeros = std::countr_zero(bitmap);  // 2
auto trailing_ones = std::countr_one(bitmap >> 2); // 1

Full Example

countr.cpp
// CodeNebula - C++20 Example: std::countr_zero and std::countr_one
// Compile: g++ -std=c++20 -Wall -Wextra -o example countr.cpp

#include <bit>
#include <bitset>
#include <cstdint>
#include <iostream>

template <typename T>
void show_countr(T val) {
    constexpr int bits = sizeof(T) * 8;
    std::cout << "  " << std::bitset<bits>(val)
              << " (" << static_cast<uint64_t>(val) << ")"
              << "  countr_zero=" << std::countr_zero(val)
              << "  countr_one=" << std::countr_one(val) << "\n";
}

int main() {
    std::cout << "=== std::countr_zero - count trailing zeros ===\n";
    std::cout << "(Counts consecutive 0-bits from the least significant bit)\n\n";

    std::cout << "uint8_t examples:\n";
    show_countr(static_cast<uint8_t>(0));     // 8 trailing zeros
    show_countr(static_cast<uint8_t>(1));     // 0 trailing zeros
    show_countr(static_cast<uint8_t>(2));     // 1 trailing zero
    show_countr(static_cast<uint8_t>(4));     // 2 trailing zeros
    show_countr(static_cast<uint8_t>(8));     // 3 trailing zeros
    show_countr(static_cast<uint8_t>(12));    // 2 trailing zeros
    show_countr(static_cast<uint8_t>(128));   // 7 trailing zeros

    std::cout << "\n=== std::countr_one - count trailing ones ===\n";
    std::cout << "(Counts consecutive 1-bits from the least significant bit)\n\n";

    std::cout << "uint8_t examples:\n";
    show_countr(static_cast<uint8_t>(0xFF)); // 8 trailing ones
    show_countr(static_cast<uint8_t>(0x0F)); // 4 trailing ones
    show_countr(static_cast<uint8_t>(0x07)); // 3 trailing ones
    show_countr(static_cast<uint8_t>(0x03)); // 2 trailing ones
    show_countr(static_cast<uint8_t>(0x01)); // 1 trailing one
    show_countr(static_cast<uint8_t>(0x00)); // 0 trailing ones

    std::cout << "\n=== 32-bit examples ===\n";
    std::cout << "countr_zero(1u)    = " << std::countr_zero(1u) << "\n";
    std::cout << "countr_zero(16u)   = " << std::countr_zero(16u) << "\n";
    std::cout << "countr_zero(1024u) = " << std::countr_zero(1024u) << "\n";
    std::cout << "countr_one(0xFFu)  = " << std::countr_one(0xFFu) << "\n";

    std::cout << "\n=== Practical: find alignment of address ===\n";
    // Trailing zeros indicate the alignment power
    for (uintptr_t addr : {0x1000uL, 0x1004uL, 0x1008uL, 0x1010uL, 0x1040uL}) {
        auto tz = std::countr_zero(static_cast<unsigned long>(addr));
        std::cout << "Address 0x" << std::hex << addr << std::dec
                  << ": aligned to 2^" << tz << " = " << (1uL << tz) << " bytes\n";
    }

    std::cout << "\n=== Practical: iterate set bits ===\n";
    uint32_t flags = 0b10110100;
    std::cout << "Set bits in " << std::bitset<8>(flags) << ": ";
    uint32_t tmp = flags;
    while (tmp != 0) {
        int pos = std::countr_zero(tmp);
        std::cout << pos << " ";
        tmp &= tmp - 1;  // Clear lowest set bit
    }
    std::cout << "\n";

    return 0;
}
Run command
g++ -std=c++20 -Wall -Wextra -o example countr.cpp