67

我试图弄清楚算术位移运算符在 C 中是如何工作的,以及它将如何影响带符号的 32 位整数。

为简单起见,假设我们在一个字节(8 位)内工作:

x = 1101.0101
MSB[ 1101.0101 ]LSB

阅读 Stack Overflow 和一些网站上的其他帖子,我发现: <<将移向 MSB(在我的情况下是向左),并用 0 填充“空”LSB 位。

并将>>移向 LSB(在我的情况下向右)并用 MS 位填充“空”位

因此,x = x << 7将导致将 LSB 移动到 MSB,并将所有内容设置为 0。

1000.0000

现在,假设我会>> 7,最后的结果。这会导致[0000.0010]? 我对吗?

我对轮班操作员的假设是否正确?

我刚刚在我的机器上测试过,**

int x = 1;   //000000000......01

x = x << 31; //100000000......00

x = x >> 31; //111111111......11 (Everything is filled with 1s !!!!!) 

为什么?

4

6 回答 6

69

负符号数的右移具有实现定义的行为。

如果您的 8 位表示一个有符号的 8 位值(因为您在切换到 8 位示例之前谈论的是“有符号的 32 位整数”),那么您有一个负数。右移可能会用原始 MSB 填充“空”位(即执行符号扩展),或者可能会移入零,具体取决于平台和/或编译器。

(实现定义的行为意味着编译器会做一些明智的事情,但以平台相关的方式;编译器文档应该告诉你什么。)


左移,如果数字开始为负数,或者移位操作会将 1 移到符号位或符号位之外,则具有未定义的行为(大多数对有符号值的操作都会导致溢出)。

(未定义的行为意味着任何事情都可能发生。)


在这两种情况下,对无符号值的相同操作都是明确定义的:“空”位将用 0 填充。

于 2010-10-24T19:11:05.853 回答
42

未为负值定义按位移位操作

对于'<<'

6.5.7/4 [...] 如果 E1 具有带符号类型和非负值,并且 E1×2 E2在结果类型中是可表示的,那么这就是结果值;否则,行为未定义。

和'>>'

6.5.7/5 [...] 如果 E1 具有带符号类型和负值,则结果值是实现定义的。

在特定实现上研究这些操作对有符号数字的行为是浪费时间,因为您不能保证它在任何其他实现上都会以相同的方式工作(例如,一个实现是您在计算机上使用您的特定的命令行参数)。

它甚至可能不适用于同一编译器的较旧或较新版本。编译器甚至可能将这些位定义为随机或未定义。这意味着相同的代码序列在跨源使用时可能会产生完全不同的结果,甚至取决于汇编优化或其他寄存器使用等因素。如果封装在一个函数中,它甚至可能不会在具有相同参数的两个连续调用的那些位中产生相同的结果。

仅考虑非负值,左移 1 ( ) 的效果与expression << 1将表达式乘以 2 的效果相同(前提是表达式 * 2 不会溢出),右移 1 ( expression >> 1) 的效果与除以2.

于 2010-10-24T19:17:48.273 回答
9

从 c++20 开始,有符号整数的按位移位运算符定义良好。

左移a<<b等效于a*2^b模数2^N,其中N是结果类型中的位数。特别1<<31是实际上是最小值int

右移a>>b相当于a/2^b,向下舍入(即朝负无穷大)。所以例如-1>>10 == -1

有关更多详细信息,请参阅https://en.cppreference.com/w/cpp/language/operator_arithmetic

(对于较旧的标准,请参见 Matthew Slattery 的答案)

于 2019-05-07T15:07:02.340 回答
6

正如其他人所说,负值的转移是实现定义的。

大多数实现将带符号的右移视为 floor(x/2 N ),方法是使用符号位填充移位的位。在实践中非常方便,因为这种操作很常见。另一方面,如果您将右移无符号整数,则移位的位将被清零。

从机器方面来看,大多数实现都有两种类型的右移指令:

  1. 正如我所解释的那样,“算术”右移(通常具有助记符 ASR 或 SRA)。

  2. 一个“逻辑”右移(通常具有助记符 LSR 或 SRL 或 SR),它可以按您的预期工作。

大多数编译器首先使用有符号类型,然后使用无符号类型。只是为了方便。

于 2010-10-24T22:32:54.493 回答
0

在 32 位编译器中

x = x >> 31;

这里 x 是有符号整数,所以第 32 位是符​​号位。

最终 x 值为 100000...000。第 32 位表示 -ive 值。

这里 x 值实现到 1 的恭维。

那么最终的 x 是 -32768

于 2017-07-05T11:24:40.803 回答
0

在我的 i7 上:

uint64_t:

0xffffffffffffffff >> 0 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 1 is 0b0111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 2 is 0b0011111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 3 is 0b0001111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 4 is 0b0000111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 62 is 0b0000000000000000000000000000000000000000000000000000000000000011
0xffffffffffffffff >> 63 is 0b0000000000000000000000000000000000000000000000000000000000000001
0xffffffffffffffff >> 64 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 65 is 0b0111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 66 is 0b0011111111111111111111111111111111111111111111111111111111111111

int64_t -1

0xffffffffffffffff >> 0 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 1 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 2 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 3 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 4 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 62 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 63 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 64 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 65 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 66 is 0b1111111111111111111111111111111111111111111111111111111111111111

int64_t 2^63-1

0x7fffffffffffffff >> 0 is 0b0111111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 1 is 0b0011111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 2 is 0b0001111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 3 is 0b0000111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 4 is 0b0000011111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 62 is 0b0000000000000000000000000000000000000000000000000000000000000001
0x7fffffffffffffff >> 63 is 0b0000000000000000000000000000000000000000000000000000000000000000
0x7fffffffffffffff >> 64 is 0b0111111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 65 is 0b0011111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 66 is 0b0001111111111111111111111111111111111111111111111111111111111111
于 2019-11-22T14:05:03.910 回答