循环(rotary/circular)移位操作是将数字的位向某个方向移动指定的位数,并将“溢出”的位移到相对的一端。在C语言中,没有内置的操作符来执行此任务;这一解决方案与标准库的可移植性以及需要明确为不同平台定义的行为历史上有关。
问题在于,标准的移位操作符(<<,>>)不执行循环移位:它们只是简单地移位,而“溢出”的位用零替代。为了执行循环移位,需要显式地组合两个移位的结果,并根据给定的位数对结果进行掩码处理。
解决方案是手动实现循环移位。对32位无符号整数来说,这看起来是这样的:
uint32_t rotate_left(uint32_t value, unsigned int shift) { return (value << shift) | (value >> (32 - shift)); } uint32_t rotate_right(uint32_t value, unsigned int shift) { return (value >> shift) | (value << (32 - shift)); }
关键特性:
操作符<<或>>可以在没有额外操作的情况下实现循环移位吗?
不可以。普通移位会用零替代溢出的位,而不是将它们移到另一边。
如果移位量等于类型大小(shift等于数字的位数),会发生什么?
行为未定义(根据C标准为Undefined Behavior),必须将移位限制在类型大小的模内。
对于signed类型,使用这些函数进行rotary shift是安全的吗?
不,总是使用无符号类型,因为对signed类型的逐位移位的行为依赖于编译器和架构而有所不同。
使用普通移位进行循环移位:
uint32_t x = 0xFA3C0F00; uint32_t y = x << 5; // 不具备循环特性
优点:
缺点:
使用手动的rotary shift函数,考虑到数据类型的大小并避免UB:
uint32_t x = 0xFA3C0F00; uint32_t y = rotate_left(x, 5);
优点:
缺点: