Bitwise Rotation in C++: std::rotl and std::rotr
Modern C++ introduces standardized support for circular bit shifts
through the std::rotl and std::rotr functions
available in the <bit> header since C++20. This
article covers how these functions perform left and right bitwise
rotations on unsigned integers, how they resolve common undefined
behavior issues associated with traditional shift operators, their
performance benefits at the hardware level, and practical examples of
their usage.
Understanding Bitwise Rotation
A bitwise rotation, also known as a circular shift, shifts all bits
of a binary value in a specified direction. Unlike standard logical or
arithmetic shift operations (<< and
>>), where shifted-out bits are discarded and vacated
positions are filled with zeros or sign bits, bitwise rotation wraps the
discarded bits back around to the opposite end of the value.
- Rotate Left (
std::rotl): Bits shifted out of the most significant position re-enter at the least significant position. - Rotate Right (
std::rotr): Bits shifted out of the least significant position re-enter at the most significant position.
The Problem with Pre-C++20 Implementations
Prior to C++20, bit rotation had to be manually implemented using combinations of shift and bitwise OR operators:
// Traditional manual left rotation
unsigned int rotate_left(unsigned int value, int shift) {
return (value << shift) | (value >> (sizeof(value) * 8 - shift));
}This manual approach introduces several hazards:
- Undefined Behavior: If
shiftis0or greater than or equal to the bit-width of the type, shifting by(sizeof(value) * 8 - shift)causes undefined behavior in C++. - Compiler Dependency: Developers relied on compiler
optimization passes to pattern-match the idiom and emit single assembly
instructions (such as
ROLorRORon x86 architectures). If the idiom was written slightly differently, the compiler might generate multiple instructions instead.
Modern C++ Implementation: std::rotl and std::rotr
Introduced in C++20, std::rotl and
std::rotr solve these issues by providing safe,
standardized, and direct access to CPU-level rotation instructions.
Requirements and Characteristics
- Header:
#include <bit> - Type Constraints: The input type
Tmust be an unsigned integer type (e.g.,unsigned char,unsigned short,unsigned int,uint32_t,uint64_t). Standard signed integer types andboolare not allowed. - Safety: Unlike the built-in shift operators,
std::rotlandstd::rotrhandle arbitrary shift values safely. If the shift count is negative, it rotates in the reverse direction. If the shift count exceeds the bit-width of the type, the shift is taken modulo the bit-width. - Qualifiers: Both functions are marked
constexprandnoexcept, making them suitable for compile-time evaluation and high-performance, exception-free contexts.
Syntax and Example Usage
#include <bit>
#include <cstdint>
#include <iostream>
int main() {
uint8_t value = 0b10000001; // 129 in decimal
// Rotate left by 1 bit: 0b10000001 -> 0b00000011
uint8_t rot_left = std::rotl(value, 1);
std::cout << "Rotate Left by 1: " << static_cast<int>(rot_left) << '\n';
// Rotate right by 1 bit: 0b10000001 -> 0b11000000
uint8_t rot_right = std::rotr(value, 1);
std::cout << "Rotate Right by 1: " << static_cast<int>(rot_right) << '\n';
// Negative shift: std::rotl with -1 is equivalent to std::rotr with 1
uint8_t neg_shift = std::rotl(value, -1);
std::cout << "Rotate Left by -1: " << static_cast<int>(neg_shift) << '\n';
// Shift exceeding bit width: modulo applied (8-bit type, shift 9 == shift 1)
uint8_t mod_shift = std::rotl(value, 9);
std::cout << "Rotate Left by 9: " << static_cast<int>(mod_shift) << '\n';
return 0;
}Key Use Cases
- Cryptography and Hashing: Algorithms such as SHA-256, MD5, and ChaCha20 heavily rely on bitwise rotations to achieve data diffusion and mixing.
- Checksums and CRC Calculations: Cyclic redundancy checks utilize bit rotations to distribute bits uniformly across registers.
- Random Number Generation: PRNG algorithms, such as xoshiro and PCG, use bit rotations to produce fast and well-distributed pseudo-random sequences.