C中〜0的值是多少?
我想获得值INT_MIN
和INT_MAX
,并且我已经尝试了INT_MAX
和~0 >> 1
因为最左边的位是符号位。 我把它们都给了-1
。
令人困惑的是为什么不是0xffffffff
结果是0xffffffff
而0x7fffffff
~0 >> 1
是0x7fffffff
?
使用:
~0U >> 1
后缀’U’表示无符号的移位行为。
所以,困惑,为什么不
0xffffffff
原来是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
? 它是:
number bits 0000 0000 0000 0000 0000 0000 0000 0001 ▲ ▲ MSB LSB
1的补码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 [按位移位运算符]
5
E1 >> E2
的结果是E1
右移E2
位的位置。 如果E1
具有无符号类型或者E1
具有有符号类型和非负值,则结果的值是E1 / 2E2
的商的整数部分。 如果E1
具有带符号类型和负值,则结果值是实现定义的。
您的要求是所谓的无符号右移>>
您可以使用无符号数找到所需的行为,这就是我将U
作为0U
后缀的0U
。
如何打印INT_MIN和INT_MAX?
因为在C中打印INT_MIN和INT_MAX有点棘手(因为设置MSB和位溢出的未定义和实现行为)所以我编写了如下代码:
#include #include /* 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 31 , 2 31 -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 [按位移位运算符]
E1 << E2
的结果是E1左移E2位位置; 腾出的位用零填充。 如果E1具有无符号类型,则结果的值为E1×2E2,模数比结果类型中可表示的最大值减1。 如果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
0的类型为int
。 所以~0
和~0 >> 1
是因为int类型的推广
〜0全是1,在2的补码中是-1,这是大多数现代实现的默认表示。
C中的右移是实现定义的。 但是大多数实现将>>
定义为类型签名时的算术移位和类型无符号时的逻辑移位
由于~0
是int
,它是有符号类型,因此~0 >> 1
将是算术右移。 因此,值被符号扩展,导致值为全1
你需要做unsigned(~0) >> 1
无法获得INT_MIN和INT_MAX,因为在C中有3种不同的签名类型实现
~0
是 -1
。 您可能遇到的每个C实现都对有符号整数使用二进制补码,因此0xffffffff
为-1
(假设为32位整数)。 ~0 >> 1
相当于将-1
除以2
; 因为我们正在进行整数运算,结果是-1
。
所有位设置int
的值取决于您的平台对int
的符号表示。 这就是发明宏INT_MIN
和INT_MAX
原因,没有办法以便携方式计算这些值。
根据维基百科文章,C通常实现算术移位。 这意味着当您右移数量0xffffffff
,最左边的位(符号位)将保留,如您所见。
但是,维基百科还提到了以下内容,因此如果使用无符号类型,则会得到逻辑移位( 0x7fffffff
结果)。
C和C ++中的>>运算符不一定是算术移位。 通常,如果在左侧使用带符号整数类型,则它只是算术移位。 如果它用于无符号整数类型,则它将是逻辑移位。
数字存储在2的0XFFFFFFFF
,所以0XFFFFFFFF
是0XFFFFFFFF
,即-1。
所以FFFFFFF(1111) >>1
给出(1111)FFFFFFF
= 0XFFFFFFFF
= -1
。
当移位unsigned
值时,C中的>>
运算符是logical shift
。 当移位有signed
值时, >>
运算符是arithmetic shift
。
因此, ~0U >> 1
给出(1111)FFFFFFF
= 0XFFFFFFFF
。
在32位系统上, 0
是0x00000000
。 ~
是按位非运算符 ,它将每0
位变为1
,反之亦然。 因此, ~0
( ~0x00000000
)给出0xffffffff
。
这反过来在二进制补码中被解释为-1
。