C中〜0的值是多少?

时间:2014-04-20 08:44:33

标签: c bit-manipulation

我希望获得值INT_MININT_MAX,并且我已尝试~0~0 >> 1,因为最左边的位是符号位。我得到了他们-1

很困惑,为什么~0原来0xffffffff~0 >> 10x7fffffff

7 个答案:

答案 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

的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后缀的原因。

如何打印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]等于[-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中的右移是实现定义的。但大多数实现在类型签名时将>>定义为算术移位,在类型为无符号时将逻辑移位定义为

由于~0int,这是签名类型,~0 >> 1将是算术右移。因此值是符号扩展,导致值全为1s

您需要unsigned(~0) >> 1

无法获得INT_MIN和INT_MAX,因为在C中有3种不同的签名类型实现

答案 2 :(得分:1)

数字存储在2的赞美中,因此~00XFFFFFFFF,即-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_MININT_MAX的原因,没有办法以便携的方式计算这些值。

答案 5 :(得分:1)

基于wikipedia文章,C通常实现算术移位。这意味着当您向右移动数量0xffffffff时,1的最左位(符号位)将被保留,如您所见。

但是,维基百科还提到了以下内容,因此如果您使用无符号类型,您将获得逻辑转换(0x7fffffff的结果)。

  

&gt;&gt; C和C ++中的运算符不一定是算术移位。   通常,如果与有符号整数一起使用,它只是一个算术移位   键入左侧。如果它用于无符号整数类型   相反,这将是一个合乎逻辑的转变。

答案 6 :(得分:1)

在32位系统上,00x00000000~bitwise not operator,它将每个0位转换为1,反之亦然。因此,~0~0x00000000)会0xffffffff

这又在Two's complement中解释为-1