2011-09-22 78 views
15

在我的编译器,下面的伪代码(值二进制替换):向右移位并有符号整数

sint32 word = (10000000 00000000 00000000 00000000); 
word >>= 16; 

产生word与位域看起来像这样:

(11111111 11111111 10000000 00000000) 

我的问题是的,我可以依赖这种行为来处理所有平台和C++编译器吗?

回答

23

从下面的链接:
INT34-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number of bits that exist in the operand

不合规代码示例(右移)
E1 >> E2结果是E1右移E2比特位置。如果E1具有无符号类型,或者如果E1具有符号类型和具有非负值,则结果的值是E1/2 E2的商的整数部分。如果E1具有符号类型和负值,所得到的值是实现定义的,可以是一个算术(签名)移:
Arithmetic (signed) shift
或的逻辑(无符号)移:
Logical (unsigned) shift
这不符合要求的代码示例未能测试右操作数是否大于或等于提升的左操作数的宽度,从而允许未定义的行为。

unsigned int ui1; 
unsigned int ui2; 
unsigned int uresult; 

/* Initialize ui1 and ui2 */ 

uresult = ui1 >> ui2; 

约右移是否被作为运算实现制作假设(签名)移位或的逻辑(无符号)移也可能导致脆弱性。见建议INT13-C. Use bitwise operators only on unsigned operands

+1

有没有建议,实际上关注这个问题?因为基于该规则的名称,它不适用于此...您只是引用了一些提供的背景信息。 –

12

不,你不能依赖这种行为。负数的右移(我假设你的例子正在处理)是实现定义的。

+0

好吧,这是公平的。我仍然想知道,如果编译器创建了一个使用这种方法的二进制文件,至少在大多数硬件中它能像预期的那样工作吗? –

+4

如果您为特定架构编译某些东西,那么在该架构的所有实现中应该都是相同的。例如,对于符号扩展和非符号扩展移位,x86有不同的移位操作,编译器决定使用哪一种移位操作。在其他体系结构中,它可能根本无法工作(请阅读:*所有内容*,而不仅仅是此行为)。 –

+0

这太可怕了...... – Claudiu

3

AFAIK整数可以表示为C++中的符号大小,在这种情况下符号扩展将填充0。所以你不能依赖这个。

+0

你说得对。该标准提出了一些要求,使得二者可以补充最佳表示,但是一般来说,有符号整数可以以实现需要的任何方式表示。 –

6

在C++中,没有。它依赖于实现和/或平台。

在其他一些语言中,是的。例如,在Java中,>>操作符被精确定义为始终使用最左边的位填充(从而保留符号)。 >>>运算符使用0填充。所以如果你想要可靠的行为,一个可能的选择是改用不同的语言。 (虽然显然,这可能不是一个选择取决于你的情况。)