2016-12-06 94 views
4

我只是給K & R C書第2章學習,比方說,我有這樣的代碼:爲什麼〜0 >> 1不移位?

#include <stdio.h> 
int 
main(void) 
{ 
    printf("0x%016llx\n", ~0); //0x00000000ffffffff 

    printf("0x%016llx\n", ~0 >> 1); //0x00000000ffffffff 
    printf("0x%016llx\n", 0x00000000ffffffff >> 1); //0x000000007fffffff 
    return 0; 
} 

我希望~0 >> 1會給0x000000007fffffff怎麼樣0x00000000ffffffff >> 1做的,這~00x00000000ffffffff值。

爲什麼~0 >> 1不移位?

+5

您的代碼調用未定義的行爲,因此所有可能的結果都是同樣有效的。要修復UB,請將'llx'更改爲'x'。然後,爲了得到你想要的行爲,把'〜0'改成'〜0u'。 –

+0

@Robᵩ - 很好的評論。應該是一個答案。 – ryyker

+1

@林果皞:您的平臺上的'〜0'不是'0x00000000ffffffff',因爲您錯誤地認爲。它只是'0xffffffff'。 – AnT

回答

6

llx格式說明符需要unsigned long long參數,但您傳遞的是int

由於~0的結果爲int且該值爲負值,因此該轉變不會給您所期望的結果。因此,執行右移將保留符號位,即1位向左移位。

把你的整型常量的ULL後綴迫使他們是正確的類型:

printf("0x%016llx\n", ~0ULL); 
printf("0x%016llx\n", ~0ULL >> 1); 
printf("0x%016llx\n", 0x00000000ffffffffULL >> 1); 

然後你會得到預期的輸出:

0xffffffffffffffff 
0x7fffffffffffffff 
0x000000007fffffff 

因爲值現在是無符號,一個0位總是被移到左邊。

2

此代碼...

printf("0x%016llx\n", ~0) 

...和您的其他類似的實施例表現出不確定的行爲,因爲~0類型(int)不對應於相應的字段的描述符,%llx,這需要一個unsigned long long int

計算表達式~0 >> 1展品實現定義(未定義)的行爲,因爲標準明確地說

E1 >> E2結果是E1右移E2位位置[但如果 E1有簽名類型和負值,結果值是實現定義的。

(C2011,6.5.7/5)

出現這種情況至少部分是因爲有一個負號的右移位的兩種不相容的解釋:

  • 一個算術 shift,其中結果與左操作數具有相同的符號,並且

  • a logical班次,其中由班次空出的職位總是填滿零。

實現可以選擇(自由地,而不只是在這些選擇之間)。實際上,這意味着便攜式代碼不應該依賴這些操作。

相關問題