我试图清楚地理解移位运算符的行为(尤其是对于边界情况),所以我设计了一个用 C++ 编写的小测试。
int a = odd_value; //321 in my case but it should not matter (the last bit to be 1)
print(0, a);
a = a << 31; // (this gives a segmentation fault, as normal because it tries the sign bit becomes 1 but all the other bits are 0).
print(0, a); //the segmentation fault happens here - it prints the minimum integer value and then gives the fault
a = (a << 1) + 1; // but if then I do this, shouldn't it set a to -1 ??
print(a); //gives 0
void print(int stackCallIndex, int nb)
{
if(nb)
{
print(++stackCallIndex, nb >> 1);
if(nb & 1) printf("%d", 1);
else printf("%d", 0);
if(stackCallIndex % 8 == 0) printf(" ");
}
}
根据您的代码,如果您尝试打印负值,我敢打赌由于无限递归会导致 stackoverflow。
void print(int stackCallIndex, int nb)
{
if(number)
{
print(++stackCallIndex, nb >> 1); // likely an infinite recursion here.
if(nb & 1) printf("%d", 1);
else printf("%d", 0);
if(stackCallIndex % 8 == 0) printf(" ");
}
}
那为什么会是无限递归呢?严格按照标准右移负符号整数是实现定义的。
在大多数实现中,它会执行 arithmetic right shift ,这意味着 1111 1100
(二进制补码 8 位中的 -4)向右移动 1 将导致 1111 1110
(二进制补码 8 位中的 -2),如您所见你总是再次填充符号位,这样你的数字就永远不会变为 0,并且 if 条件始终为真。
通常对有符号值进行位操作不是一个好主意,它们在少数情况下涉及实现/未定义行为。在使用位操作之前,最好将所有值都转换为无符号。
我是一名优秀的程序员,十分优秀!