C中〜0的值是多少?

das*_*tan 9 c bit-manipulation

我想要得到的价值INT_MININT_MAX,和我试过~0~0 >> 1,因为最左边的位为符号位.我得到了他们两个-1.

它太混乱了,为什么不~0成为0xffffffff~0 >> 1将来0x7fffffff

Gri*_*han 20

使用:

~0U >> 1
Run Code Online (Sandbox Code Playgroud)

后缀'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) 
Run Code Online (Sandbox Code Playgroud)

现在~是按位运算符然后将所有位翻转0为:

BIT NUMBER    31                                     0
               ?                                     ?
number bits    1111 1111 1111 1111 1111 1111 1111 1111
               ?                                     ? 
              MSB                                   LSB
Run Code Online (Sandbox Code Playgroud)

因为MSB = 1这个表示被视为负数,其大小是使用2'补充数学得到的-1.

怎么样?

什么是1?它是:

number bits    0000 0000 0000 0000 0000 0000 0000 0001 
               ?                                     ? 
              MSB                                   LSB
Run Code Online (Sandbox Code Playgroud)

1的补充 1

number bits    1111 1111 1111 1111 1111 1111 1111 1110
               ?                                     ? 
              MSB                                   LSB
Run Code Online (Sandbox Code Playgroud)

2'complement?加上1一个补码,即:

number bits    1111 1111 1111 1111 1111 1111 1111 1111
               ?                                     ? 
              MSB                                   LSB
Run Code Online (Sandbox Code Playgroud)

当你得到的时候一样~0吗?这就是你获得-1输出的原因.

现在>>转移运营商?

在C >>的大多数实现中,运算符被定义为算术右移,其保留符号位MSB.所以~0 >> 1注意到但-1仍然相同.

6.5.7 [按位移位运算符]

5 结果E1 >> E2E1右移位E2位置.如果E1具有无符号类型或者E1具有有符号类型和非负值,则结果的值是商的整数部分E1 / 2E2.如果E1具有有符号类型和负值,则结果值是实现定义的.

您的要求就是所谓的无符号右移>>,你所需要的行为,可以发现使用,这就是为什么我后缀无符号数U0U.

如何打印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;
}
Run Code Online (Sandbox Code Playgroud)

看到它正在执行@ codepad,它的输出是:

INT_MIN  = -2147483648
INT_MAX  = 2147483647 
Run Code Online (Sandbox Code Playgroud)

这段代码是如何工作的?

32位数字范围的注意事项[-2147483648, 2147483647]等于.[-231, 231 -1 ]

INT_MIN: -2 31 == -2147483648是:

    1000 0000 0000 0000 0000 0000 0000 0000 
    ?                                     ? 
    MSB                                   LSB
Run Code Online (Sandbox Code Playgroud)

在表达式中1U << ((sizeof(int) * CHAR_BIT) - 1),我将LSB(即1)的第一位移位到MSB的最左侧,并且因为在C中,当操作数是烧写类型时设置有符号位是未定义的行为所以我使用无符号的1U.

6.5.7 [按位移位运算符]

结果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
Run Code Online (Sandbox Code Playgroud)