C中〜0的值是多少?

我想获得值INT_MININT_MAX ,并且我已经尝试了INT_MAX~0 >> 1因为最左边的位是符号位。 我把它们都给了-1

令人困惑的是为什么不是0xffffffff结果是0xffffffff0x7fffffff ~0 >> 10x7fffffff

使用:

 ~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中的右移是实现定义的。 但是大多数实现将>>定义为类型签名时的算术移位和类型无符号时的逻辑移位

由于~0int ,它是有符号类型,因此~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_MININT_MAX原因,没有办法以便携方式计算这些值。

根据维基百科文章,C通常实现算术移位。 这意味着当您右移数量0xffffffff ,最左边的位(符号位)将保留,如您所见。

但是,维基百科还提到了以下内容,因此如果使用无符号类型,则会得到逻辑移位( 0x7fffffff结果)。

C和C ++中的>>运算符不一定是算术移位。 通常,如果在左侧使用带符号整数类型,则它只是算术移位。 如果它用于无符号整数类型,则它将是逻辑移位。

数字存储在2的0XFFFFFFFF ,所以0XFFFFFFFF0XFFFFFFFF ,即-1。
所以FFFFFFF(1111) >>1给出(1111)FFFFFFF = 0XFFFFFFFF = -1

当移位unsigned值时,C中的>>运算符是logical shift 。 当移位有signed值时, >>运算符是arithmetic shift
因此, ~0U >> 1给出(1111)FFFFFFF = 0XFFFFFFFF

在32位系统上, 00x00000000~是按位非运算符 ,它将每0位变为1 ,反之亦然。 因此, ~0~0x00000000 )给出0xffffffff

这反过来在二进制补码中被解释为-1