以负数执行按位移位是否有效?例如,如果我有以下代码:
#include <stdint.h>
uint32_t reverse_bits (uint32_t n)
{
uint32_t result = 0;
for (int i = 0; i < 32; i++)
{
uint32_t bit = n & (1 << i);
bit <<= 31 - i * 2;
result |= bit;
}
return result;
}
这是我可以期望在所有架构上工作的东西(具体来说,表达x << shift_amt
的结果,其中shift_amount < 0
是真的,相当于x >> -shift_amt
)?
注意:这不是关于对负数(即-1 << 1
)执行按位移位的行为的问题。
这是完整的测试程序:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
uint32_t reverse_bits (uint32_t n)
{
uint32_t result = 0;
for (int i = 0; i < 32; i++)
{
uint32_t bit = n & (1 << i);
bit <<= 31 - i * 2;
result |= bit;
}
return result;
}
void print_bits (uint32_t n)
{
for (int i = 0; i < 32; i++)
putchar(n & (1 << i) ? '1' : '0');
putchar('\n');
}
int main ()
{
for (int i = 0; i < 5; i++)
{
uint32_t x = rand();
x |= rand() << 16;
print_bits(x);
print_bits(reverse_bits(x));
putchar('\n');
}
}
如前所述,根据undefined behavior的6.5.7p3部分,按负值移动会调用C standard。
而不是试图猜测什么时候你可以摆脱负面转变,改变你的代码,所以你不需要。
屏蔽掉您想要的位后,将其移回位置0,然后将其移至所需位置。此外,请确保将常量1
更改为1ul
,以便最终不会将有符号值移入符号位或超过int
的宽度。还要注意使用sizeof
来避免硬编码魔法数字,如32。
unsigned long reverse_bits (unsigned long n)
{
unsigned long result = 0;
for (int i = 0; i < sizeof(unsigned long) * CHAR_BIT; i++)
{
unsigned long bit = ((n & (1ul << i)) >> i);
unsigned long shift = (sizeof(unsigned long) * CHAR_BIT) - i - 1;
result |= bit << shift;
}
return result;
}