c不能将负数转移到右边

时间:2018-03-21 01:56:32

标签: c bit-manipulation

我正在经历'K& R'的C语言。现在我正在做按位节。我很难理解以下代码。

int mask = ~0 >> n;

我正在使用它来掩盖另一个二进制文件的左侧像这样。     0000 1111     1010 0101 //随机数

我的问题是当我打印var mask时它仍然是负-1。假设n为4.我认为移位〜0即-1为15(0000 1111)。

感谢答案

3 个答案:

答案 0 :(得分:5)

对负值执行右移会产生实现定义的值。正如您在案例中看到的那样,大多数托管实施将在左侧1位移位,但不一定非必要。

无符号类型以及带符号类型的正值在向右移位时始终在左侧0位移位。因此,您可以使用无符号值来获得所需的行为:

unsigned int mask = ~0u >> n;

C standard的第6.5.7节

中记录了此行为
  

5 E1>>的结果E2 E 1右移 E2 位位置。如果 E1 具有无符号类型或 E1 具有签名类型且非负   值,结果的值是商的不可分割的一部分    E1 / 2 E2 。如果 E1 有签名类型和负值,   结果值是实现定义的。

答案 1 :(得分:3)

右移负有符号整数是一种实现定义的行为,通常(但不总是)用左边的一个而不是零填充左边的行为。这就是为什么无论你移动了多少位,它总是-1,因为左边总是被一个填充。

当您移位无符号整数时,左侧将始终用零填充。所以你可以这样做:

unsigned int mask = ~0U >> n;
                      ^

你还应该注意int通常是2或4个字节,这意味着如果你想获得15,你需要右移12或28位而不是4位。你可以使用{{1而是:

char

答案 2 :(得分:1)

在C和许多其他语言中,>>签名的变量(例如int)上执行时(通常)为arithmetic right shift。这意味着从左侧移入的新位是前一个最高有效位(MSB)的副本。这样可以保留两个赞美负数的符号(在这种情况下是值)。

这与logical right shift形成对比,其中MSB始终用零位替换。当您的变量无符号(例如unsigned int)时,会应用此选项。

来自维基百科:

  

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

在你的情况下,如果你计划在某种程度上工作(即使用面具等),我强烈推荐两件事:

  1. 使用无符号值。
  2. 使用<stdint.h>之类特定尺寸的类型,例如uint32_t