由于位溢出代表-1?

时间:2018-08-20 16:17:18

标签: c bit

嘿,我试图在浏览和阅读网络后找出-1 << 4(左)移位FFF0的原因,我才知道“负”数字有一个符号位,即1。所以因为"-1"意味着额外的1位,即(33)位,这是不可能的,这就是为什么我们将-1视为1111 1111 1111 1111 1111 1111 1111 1111

例如:-

#include<stdio.h>
void main()
{
printf("%x",-1<<4);
} 

在此示例中,我们知道–

Internal representation of -1 is all 1’s 1111 1111 1111 1111 1111 1111 1111 1111 in an 32 bit compiler.
When we bitwise shift negative number by 4 bits to left least significant 4 bits are filled with 0’s
Format specifier %x prints specified integer value as hexadecimal format
After shifting 1111 1111 1111 1111 1111 1111 1111 0000 = FFFFFFF0 will be printed.

上述来源 http://www.c4learn.com/c-programming/c-bitwise-shift-negative-number/

2 个答案:

答案 0 :(得分:6)

首先,根据C标准,未定义带负号有符号变量的左移结果。因此,从严格的语言律师角度来看,问题“ 为什么-1 << 4导致XYZ ”的答案是“ ”,因为标准未指定结果应该是什么。

但是,您的特定编译器实际上在做什么,将two's-complement representation的-1左移,就好像该表示形式是无符号值一样。由于-1的32位二进制补码表示为0xFFFFFFFF(或二进制形式的11111111 11111111 11111111 11111111),所以将左移4位的结果为0xFFFFFFF011111111 11111111 11111111 11110000。这是将结果存储回(有符号)变量中的结果,该值是-16的二进制补码表示。如果将结果打印为整数(%d),则结果为-16。

这是大多数现实世界中的编译器会执行的操作,但并不依赖它,因为C标准不需要它。

答案 1 :(得分:4)

首先,教程使用void main。在评估本教程的质量时,comp.lang.c frequently asked question 11.15应该引起关注:

  

问:我一直在使用的《 C语言编程傻瓜》 一书始终使用void main()

     

A:也许作者认为自己是目标受众。许多书籍在示例中都不必要地使用void main(),并断言它是正确的。他们错了,或者他们假设每个人都为能正常工作的系统编写代码。

也就是说,该示例的其余部分是不明智的。 C标准未定义有符号左移的行为。但是,允许编译器实现定义针对标准故意开放的情况下的行为。例如,GCC does define

  • 所有带符号的整数均具有two's-complement格式
  • <<在带负号的数字上定义明确,>>的工作方式就像带符号扩展名一样。

因此,保证在 GCC -1 << 4产生-16;给定32位int,这些数字的位表示分别为1111 1111 1111 1111 1111 1111 1111 11111111 1111 1111 1111 1111 1111 1111 0000

现在,这里还有另一个未定义的行为:%x期望的参数为unsigned int,但是您传入的是signed intunsigned int中无法表示的值。但是,在GCC /上具有常见libc 的行为是有符号整数的字节被解释为无符号整数,1111 1111 1111 1111 1111 1111 1111 0000以二进制形式出现,十六进制为{{1} }。

但是,可移植的C程序实际上应该从不

  • 假设二进制补码表示法-当表示法很重要时,请使用FFFFFFF0甚至是unsigned int
  • 假设负数上的uint32_t<<具有一定的行为
  • 使用>>和带签名的数字
  • %x

具有相同行为的,针对相同用例的可移植(C99,C11,C17)程序将是

void main