2014-09-10 53 views
0

我在一個函數上調用此代碼,以便將有符號整數n設置爲零,但行爲奇怪。兩條等價線評估不同的結果[bit-shifting]

printf("n is %d \n", n);                                                    
printf("shift1 %d \n", -1 << (32 + (~0 + 1))); 
printf("shift2 %d \n", -1 << (32 + (~n + 1))); 

打印

n is 0 
shift1 0 
shift2 -2 

我不知道爲什麼會這樣,由於n == 0

+0

'n'是什麼類型? – cdhowie 2014-09-10 23:04:13

+0

@cdhowie n是一個有符號整數。 – Miles 2014-09-10 23:04:56

+1

注意左移一個負整數是未定義的行爲,所以在技術上這個輸出是C規範允許的。我們可以推斷它在你的特定編譯器上的行爲,但我們不能推斷它將如何表現,因此我們不能提供答案。 – cdhowie 2014-09-10 23:05:43

回答

3

這奇怪的行爲,因爲應用到負整數<<運營商的行爲未定義。因此,任何結果都是此代碼的有效結果。

由於行爲沒有定義,我們不能推理它。所以我們真的不能說爲什麼它不一樣,只是根據C規範它是允許有所不同。

當我嘗試它時,我得到兩個班次的結果爲零。 (我們的結果都不是更正確的!這只是爲了表明調用未定義行爲的相同程序在不同的編譯器和/或體系結構上確實會產生不同的結果。)

+0

即使我們將'-1'更改爲'1',我們仍然存在未定義的行爲,因爲移位計數過大。 – AlexD 2014-09-10 23:41:31

1

在任何情況下將負數轉移任意數(甚至0),在任何方向,總是Undefined Behavior (UB)
移動一個有符號的數值也是如此,以至於數學結果不能存儲在它的類型中。

一個不能推斷未定義的行爲。

1

甚至改變-11後我可以重現的差異(與Visual Studio,在DEBUG配置):

printf("n is %d \n", n); 
printf("shift1 %d \n", 1 << (32 + (~0 + 1))); 
printf("shift2 %d \n", 1 << (32 + (~n + 1))); 

對於第一線,我得到一個warning

警告C4293:'< <':移位計數負值或太大,未定義的行爲

問題是,在第一種情況下,我的編譯器在編譯時評估表達式,發現操作數太大,第二種情況 - 運行時。

在我的情況下,在編譯時,表達被評估爲0,在運行時 - 到1

int n = 0; 
    mov   dword ptr [n],0 

auto x = 1 << (32 + (~0 + 1)); 
    mov   dword ptr [x],0 

auto y = 1 << (32 + (~n + 1)); 
    mov   ecx,dword ptr [n] 
    not   ecx 
    add   ecx,21h 
    mov   eax,1 
    shl   eax,cl 
    mov   dword ptr [y],eax 

RELEASE模式下,結果都是一樣的。