为什么在同一语句中左移和右移会产生不同的结果?

Why does left shift and right shift in the same statement yields a different result?

本文关键字:结果 语句 为什么 左移 右移      更新时间:2023-10-16

考虑以下示例:

第一个例子:

short x=255;
x = (x<<8)>>8;
cout<<x<<endl;

第二个案例:

short x=255;
x = x<<8;
x = x>>8;
cout<<x<<endl;

第一种情况的输出是255,而第二种情况的输出是-1。-1作为输出是有意义的,因为CPP进行了算术右移。下面是x的中间值,以获得-1作为输出。

x: 0000 0000 1111 1111  
x<<8:1111 1111 0000 0000 
x>>8:1111 1111 1111 1111

为什么在第一种情况下不发生相同的机制?

这种差异是两个因素造成的。

  1. c++标准没有规定整型的最大值。该标准只指定了每个整数类型的最小大小。在您的平台上,short是16位值,int s至少是32位值。

在您的第一个示例中,short值自然地被提升为int,这至少是32位,因此左移和右移在转换回short之前对int进行操作。

在第二个示例中,在第一次左移操作之后,结果值再次转换回short,并且由于2的补码算法,它最终是一个负值。右移结束了负号扩展,导致最终结果为-1。

你刚才看到的是符号扩展:

符号扩展是计算机算术中的一种操作,在增加二进制数的位数的同时保持该数的符号(正/负)和值。这是通过将数字附加到数字的最高有效侧来完成的,其过程取决于所使用的特定有符号数字表示。

例如,如果用6位来表示数字"00 1010"(十进制正10)和符号扩展操作将字长增加到16位,那么新的表示就是简单的"0000 0000 0000 1010"。因此,该值和该值为正的事实都被保留。

如果用10位来表示值"11 11110001 "(十进制负15)使用二进制补码,并将这一符号扩展为16位,新的表示形式为"1111 1111 1111 0001"。因此,通过在左侧填充1,保留了负号和原始数字的值。

你一直右移到你的short变成负的点,然后当你移回来时,你得到符号扩展。

在第一种情况下不会发生这种情况,因为移位没有应用于short。它应用于255,它不是一个短类型,而是默认的整型(可能是int)。只有当它已经被移回后才会被强制转换:

on the stack:     0000 0000 0000 0000 0000 0000 1111 1111
<<8
on the stack:     0000 0000 0000 0000 1111 1111 0000 0000
>>8
on the stack:     0000 0000 0000 0000 0000 0000 1111 1111
convert to short: 0000 0000 1111 1111