2017-08-01 17 views
-8

爲了優化我的cpp代碼,我試圖在某些情況下使用Right Shifting。這裏有一個例子:
是否正確移動cpp和java中負數的未定義行爲?

int main() 
{ 
    int i = (1 - 2) >> 31; // sizeof(int) == 4 
    ... 
    ... 
} 

我打印的i和我-1。這意味着如果數字爲負值,它將使用1而不是0來填充空位。換句話說,-1 >> 31如下工作:

1111...1 <--- the result of (1 - 2), which is -1 
1111...1 <--- -1 >> 31, 1 is used to fill in the empty position 

我只是想知道,如果這種行爲被明確定義或沒有?

如果是cpp中的UB,那麼在Java中呢?

+1

可能的重複[是左移(<<)在C++ 11中的一個負整數未定義行爲?](https://stackoverflow.com/questions/19593938/is-left-shifting-a-negative- integer-undefined-behavior-in-c11) – user0042

+0

在Java中,絕對不是未定義的。 '>>'符號擴展名,'>>>'不。請參閱[Java™教程 - 位移和位移運算符](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html)或權威源語言Java語言規範[15.19。 Shift運算符](https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.19)。 – Andreas

+1

*「在Java中怎麼樣?」* - 爲什麼停留在Java,在C#和Rust中詢問它。 – StoryTeller

回答

1

。它是實現定義的。

根據C++ 03 5.8/3限定向右移位:

E1 E2 >>值是E1右移E2位位置。如果E1具有 無符號類型,或者如果E1具有帶符號類型和非負值,則結果值是E1 的商的整數部分除以提高到功率E2的數量2。 如果E1有一個帶符號的 類型和一個負值,則結果值爲 實現定義。

欲瞭解更多信息,請參閱此link

+0

https://stackoverflow.com/questions/11227809/why-is-it-faster-to-process-a-sorted-array-than-an-unsorted-array你能讀到接受的答案的第五評論在這個題?我不太明白他的意思...... IB或UB ...... – Yves

+0

@Yves如果你的意思是說「右移一個負號的整數是IB」,那麼沒有太多的人可以添加它使其更清晰。 – molbdnilo

+0

@molbdnilo現在,我的理解是:不要移動任何位來覆蓋符號位,因爲它是UB,這意味着左移一個大的有符號整數是危險的。而右移是IB ... – Yves

0

爪哇,的>>行爲是負數(見下文)良好定義

C++,的>>行爲是未定義負數(見answer by rsp)。


引用Java語言規範,§15.19. Shift Operators

Ñ值>>小號Ñ右移小號比特位置用符號擴展。由此產生的值是floor(n/2 s。對於非負值n,這相當於如由整數除法運算符I所計算的將整數除法截斷兩倍於功率s

Ñ>>>小號值是Ñ右移小號比特位置具有零擴展,其中:

  • 如果Ñ是正,那麼結果與相同n >> s

  • 如果Ñ爲負,左側操作數的類型是int,那麼結果是等於表達式(N >> S)+(2 < <〜多個)的。

  • 如果Ñ爲負,左側操作數的類型是long,那麼結果是等於表達式(N >> S)+的(2L < <〜多個)

+0

對於C++,行爲*是*定義的,但允許定義在不同系統之間變化。據說它是做硬件的。 –

+0

@BoPersson這意味着如果你不知道你的代碼在哪裏運行,那麼它是未定義的,但我明白你的區別。 – Andreas

+0

@Andreas:未定義的行爲被現代編譯器解釋爲以「優化」名義行爲無效的邀請,這與產生Implemnentation-Defined或Unspecified值完全不同。例如,給定'unsigned mulMod65536(unsigned short x,unsigned short y){return(x * y)&0xFFFF;}',如果'x * y'超過0x7FFFFFFF',可能會看不到任何奇怪的原因。 ,但是在gcc中,如果'x * y'不適合'int',這樣的函數有時會產生奇怪的副作用。實施定義不允許這樣的許可證。 – supercat

1

默認情況下它是帶符號的int。範圍是-32767至32767,位範圍-11111111111111111至+111111111111111左邊的第一位用作負指示符或正指示符。所有的算術運算都將以2的補碼方式完成。一般來說,負int表示兩個互補方法,即以你爲例來表示-1如何表示。

4 Bytes = 32 bits 
0000 0000 0000 0000 0000 0000 0000 0000 
how represent 1 
0000 0000 0000 0000 0000 0000 0000 0001 
Then we invert the digits. 0 becomes 1, 1 becomes 0. 
1111 1111 1111 1111 1111 1111 1111 1110 
Then we add 1. 
1111 1111 1111 1111 1111 1111 1111 1111 
This is how -1 is represented 

負數的右移被限定在1s至移位到最高位的位置,然後在一個2的補碼錶示將表現爲一個算術移位 - 右移位乘N的結果將與2N相除,向負無窮大舍入。所以移位-1 -1 現在採取其它數量 例如, 如果有8位二進制補二進制數表示讓-3

0000 0011 
    Then we invert the digits. 
    1111 1100 
    Then we add 1. 
    1111 1101 

11111101代表-3十進制,和你執行算術右移1以給出11111110,其十進制表示-2,這與將-3除以2^1相同,給出-1.5,其向負無窮向舍入導致-2。

+0

對於一個新手來說這是一個很好的答案......並且只是爲了記錄:不要忘記接受答案......即使對於已經關閉的問題也適用您。現在你已經達到了這個水平,並且快樂的投票,;-) – GhostCat

相關問題