考虑以下示例:
第一种情况:
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进行算术右移。以下是获取-1作为输出的x的中间值。
x: 0000 0000 1111 1111
x<<8:1111 1111 0000 0000
x>>8:1111 1111 1111 1111
为什么在第一种情况下不会发生相同的机制?
答案 0 :(得分:12)
差异是两个因素的结果。
C ++标准未指定整数类型的最大值。标准仅指定每个整数类型的最小大小。在您的平台上,short
是16位值,int
s至少是32位值。
第二个因素是two's complement算术。
在您的第一个示例中,short
值自然地提升为int
,至少为32位,因此左移和右移在int
上运行,之前转换回short
。
在第二个示例中,在第一个左移位操作之后,结果值再次转换回short
,并且由于二进制补码算法,它最终为负值。右移最终符号扩展负值,最终结果为-1。
答案 1 :(得分:1)
您刚观察到的是sign extension:
符号扩展是计算机算术中增加二进制数的位数同时保留数字符号(正/负)和值的操作。这是通过将数字附加到数字的最重要的一侧,遵循取决于所使用的特定有符号数字表示的过程来完成的。
例如,如果使用六位来表示数字“00 1010”(十进制正10)并且符号扩展操作将字长增加到16位,则新表示仅为“0000 0000 0000 1010”。因此,价值和价值为正的事实都得以维持。
如果使用十位来表示使用二进制补码的值“11 1111 0001”(十进制负15),并且这是符号扩展到16位,则新表示为“1111 1111 1111 0001”。因此,通过在左侧填充1,可以保持负号和原始数值。
你必须一直转移到你的空位变为负数的位置,然后当你转回时,你会得到符号延伸。
在第一种情况下不会发生这种情况,因为转移不适用于短期。它适用于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