用途:
~0U >> 1
后缀“U”表示无符号移位行为。
所以,很困惑为什么不是~0 原来是0xffffffff?
看,0 用四个字节表示:
BIT NUMBER 31 0
▼ ▼
number bits 0000 0000 0000 0000 0000 0000 0000 0000
▲ ▲
MSB LSB
LSB - Least Significant Bit (numbered 0)
MSB - Most Significant Bit (numbered 31)
现在~ 是按位非运算符,然后将0 中的所有位翻转为:
BIT NUMBER 31 0
▼ ▼
number bits 1111 1111 1111 1111 1111 1111 1111 1111
▲ ▲
MSB LSB
由于 MSB = 1,此表示被视为负数,其大小是使用 2' 补码计算得出的,即 -1。
如何?
1 是什么?它是:
number bits 0000 0000 0000 0000 0000 0000 0000 0001
▲ ▲
MSB LSB
1 的补码
number bits 1111 1111 1111 1111 1111 1111 1111 1110
▲ ▲
MSB LSB
2'补码?在一个补码中添加1,即:
number bits 1111 1111 1111 1111 1111 1111 1111 1111
▲ ▲
MSB LSB
这和你得到 ~0 时一样吗?这就是为什么你得到-1 输出。
现在 >> 移位运算符?
在 C 的大多数实现中 >> 运算符被定义为算术右移,它保留符号位 MSB。所以~0 >> 1 注意到但-1 保持不变。
5 E1 >> E2 的结果是E1 右移E2 位位置。如果E1 具有无符号类型或E1 具有带符号类型和非负值,则结果的值是E1 / 2E2 商的整数部分。如果E1 具有带符号类型和负值,则结果值是实现定义的。
您的要求是所谓的无符号右移>>,您需要的行为可以使用无符号数找到,这就是我将U 后缀为0U 的原因。
如何打印INT_MIN和INT_MAX?
因为在 C 中打印 INT_MIN 和 INT_MAX 有点棘手(因为设置 MSB 和位溢出的未定义和实现行为),所以我编写了如下代码:
#include <stdio.h>
#include<limits.h> /* include for CHAR_BIT */
int main(){
int my_int_min = 1U << ((sizeof(int) * CHAR_BIT) - 1);
int my_int_max = ~0U >> 1;
printf("INT_MIN = %d\n", my_int_min);
printf("INT_MAX = %d\n", my_int_max);
return 0;
}
看到它执行@codepad,它的输出是:
INT_MIN = -2147483648
INT_MAX = 2147483647
这段代码是如何工作的?
注意 32 位数字范围是 [-2147483648, 2147483647],等于 [-2<sup>31</sup>, 2<sup>31</sup> -1 ]。
INT_MIN: -231 == -2147483648 是:
1000 0000 0000 0000 0000 0000 0000 0000
▲ ▲
MSB LSB
在表达式1U << ((sizeof(int) * CHAR_BIT) - 1) 中,我将LSB(即1)的第一位移到MSB 的最左侧,并且因为在C 中,设置有符号位是未定义的行为当操作数是单数类型时所以我用了一个未签名的1U。
E1 << E2 的结果是 E1 左移 E2 位位置;空出的位用零填充。如果 E1 具有无符号类型,则结果的值为 E1 × 2E2 ,比结果类型中可表示的最大值多模一减少。 如果 E1 有带符号类型和非负值,并且 E1 × 2E2 在结果类型中是可表示的,那么这就是结果值;否则,行为未定义。
要注意的另一点是我使用了 CHAR_BIT 一个在limits.h 中定义的标准宏,它告诉C 实现中一个字符中的位数(请记住:字符始终是一个字节大小,但一个字节中的位数可以是不同系统上的不同并不总是保证为 8)。
INT_MAX: 231 -1 == 2147483647
0111 1111 1111 1111 1111 1111 1111 1111
▲ ▲
MSB LSB