我希望获得值INT_MIN
和INT_MAX
,并且我已尝试~0
和~0 >> 1
,因为最左边的位是符号位。我得到了他们-1
。
很困惑,为什么~0
原来0xffffffff
和~0 >> 1
为0x7fffffff
?
答案 0 :(得分:20)
使用:
~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'complement?将1
添加到一个补码中,即:
number bits 1111 1111 1111 1111 1111 1111 1111 1111
▲ ▲
MSB LSB
就像你得到~0
时一样?这就是你得到-1
输出的原因。
在大多数C>>的实施中运算符定义为算术右移,它保留符号位MSB。所以~0 >> 1
注意到了,-1
仍然相同。
6.5.7 [Bitwise shift operators]
5
E1 >> E2
的结果是E1
右移E2
位位置。如果E1
具有无符号类型或E1
具有有符号类型和非负值,则结果的值是E1 / 2E2
的商的不可分割部分。如果E1
具有签名类型和负值,则结果值是实现定义的。
您的要求是所谓的无符号右移>>
,您可以使用无符号数查找所需的行为,这就是我将U
作为0U
后缀的原因。
因为在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]
等于[-231, 231 -1 ]
。
INT_MIN: -2 31 == -2147483648:
1000 0000 0000 0000 0000 0000 0000 0000
▲ ▲
MSB LSB
在表达式1U << ((sizeof(int) * CHAR_BIT) - 1)
中,我将LSB(即1)的第一位移位到MSB的最左侧,并且因为在C中,当操作数是烧写类型时,设置有符号位是未定义的行为 所以我使用了无符号的1U。
6.5.7 [Bitwise shift operators]
E1 << E2
的结果是E1左移E2位位置;腾出的位用零填充。如果E1具有无符号类型,则结果的值为E1×2E2,比结果类型中可表示的最大值减少一个模数。 如果E1具有带符号类型和非负值,并且E1×2E2在结果类型中可表示,那么这就是结果值;否则,行为未定义。
另一点值得注意的是我使用CHAR_BIT定义了limits.h中定义的标准宏,它告诉C实现中一个字符的位数(请记住:char总是一个字节大小,但一个字节中的位数可以是不同系统的不同并不总是保证8)。
INT_MAX: 2 31 -1 == 2147483647
0111 1111 1111 1111 1111 1111 1111 1111
▲ ▲
MSB LSB
答案 1 :(得分:4)
0的类型为int
。 ~0
和~0 >> 1
也是如此,因为int类型提升
~0全是1,在2的补码中是-1,这是大多数现代实现的默认表示。
C中的右移是实现定义的。但大多数实现在类型签名时将>>
定义为算术移位,在类型为无符号时将逻辑移位定义为
由于~0
是int
,这是签名类型,~0 >> 1
将是算术右移。因此值是符号扩展,导致值全为1s
您需要unsigned(~0) >> 1
无法获得INT_MIN和INT_MAX,因为在C中有3种不同的签名类型实现
答案 2 :(得分:1)
数字存储在2的赞美中,因此~0
为0XFFFFFFFF
,即-1。
因此FFFFFFF(1111) >>1
会(1111)FFFFFFF
= 0XFFFFFFFF
= -1
。
当移动unsigned
值时,C中的>>
运算符为logical shift
。在移动signed
值时,>>
运算符为arithmetic shift
因此,~0U >> 1
会(1111)FFFFFFF
= 0XFFFFFFFF
。
答案 3 :(得分:1)
~0
-1
。您可能遇到的每个C实现都使用了对有符号整数的补码,因此0xffffffff
为-1
(假设为32位整数)。 ~0 >> 1
相当于将-1
除以2
;因为我们正在进行整数运算,结果是-1
。
答案 4 :(得分:1)
所有位集int
的值取决于您的平台对int
的符号表示。这就是发明宏INT_MIN
和INT_MAX
的原因,没有办法以便携的方式计算这些值。
答案 5 :(得分:1)
基于wikipedia文章,C通常实现算术移位。这意味着当您向右移动数量0xffffffff
时,1
的最左位(符号位)将被保留,如您所见。
但是,维基百科还提到了以下内容,因此如果您使用无符号类型,您将获得逻辑转换(0x7fffffff
的结果)。
&gt;&gt; C和C ++中的运算符不一定是算术移位。 通常,如果与有符号整数一起使用,它只是一个算术移位 键入左侧。如果它用于无符号整数类型 相反,这将是一个合乎逻辑的转变。
答案 6 :(得分:1)
在32位系统上,0
为0x00000000
。 ~
是bitwise not operator,它将每个0
位转换为1
,反之亦然。因此,~0
(~0x00000000
)会0xffffffff
。
这又在Two's complement中解释为-1
。