2011-09-22 79 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填充。所以如果你想要可靠的行爲,一個可能的選擇是改用不同的語言。 (雖然顯然,這可能不是一個選擇取決於你的情況。)