einpoklum
einpoklum

Reputation: 131544

What type should I use for the number of bits in a fundamental type?

Fundamental types in C++ have sizes between 1 and 8 (perhaps 16), on 64-bits operating systems. That means the number of bits they take up in memory is no higher than 128, i.e. the number of bits fits in an uint8_t.

Now, suppose I write some function which takes such a number of bits. For example, suppose it's

template <typename T>
inline void clear_bit(T& x, magic_type bit_index ) {
    static_assert(std::is_fundamental_v<T>, "Go away.");
    x = x & ~(T{1} << bit_index);
}

I'm wondering what to use for magic_type: Should it be a uint8_t? Or maybe it should be just be an int, since I would need to check for validity anyway, even for a uint8_t case, and with int being a more "natural" type for numbers?

To make this question less about your individual opinion: Is one of the options generally considered more idiomatic? If not, can you find good enough reasons for both choices? Or perhaps suggest a third one?

Upvotes: 2

Views: 162

Answers (1)

Whatever type you use for bit_index in the expression T{1} << bit_index, it will be promoted to int or unsigned int in any case and the result of T{1} << bit_index itself is the promoted type of T{1}. This means that x & ~(T{1} << bit_index) always yield a type that is at least 'as large as' an int.

The expression T{1} << bit_index is well defined only if
bit_index >= 0 && bit_index < (sizeof +T{}) * CHAR_BIT). The subsequent assignment to x may still truncate the result.

As a rule of thumb, if you intend to use a variable in arithmetic expressions, use int or unsigned int. unsigned is usually preferable in bitwise arithmetic contexts, otherwise just use signed.

Bottom line: Use unsigned int, or possibly signed int.

Upvotes: 3

Related Questions