2014-02-14 60 views
3

我受的size_t一些行爲,我注意到困惑大得多:爲size_t爲0x1 << 31比爲size_t爲0x1 << 30

size_t zero = 0x1 << 32; 
size_t big = 0x1 << 31; 
size_t not_as_big = 0x1 << 30; 
printf("0x1<<32: %zx\n0x1<<31: %zx\n0x1<<30: %zx\n", zero, big, not_as_big); 

結果:

0x1<<32: 0 
0x1<<31: ffffffff80000000 
0x1<<30: 40000000 

現在,我明白了size_t只保證至少是一個16位無符號整數,但我不明白爲什麼0x1<<31結束了它所做的值 - 試圖分配18艾字節在我的程序上做了一個數字。

我在x86_64上使用LLVM。

+4

符號擴展... – Mysticial

回答

9

移位符號整數,這樣1的進入符號位的位置,甚至進一步是用C不確定,所以編譯器就可以做到以下幾點:

0x1 << 32 

這裏編譯器看到一個32位int(0x1)被移位了32位。由於編譯器可以按照與更正確的轉換一致的方式自由解釋它,因此它會將其解釋爲0x1_0000_0000並嘗試將其轉換爲32位int,結果爲0x0000_0000,然後看到稍後將結果分配給一個size_t,通常是64位:0x0000_0000_0000_0000

0x1 << 31 

和以前一樣,編譯器就可以做任何它似乎是正確的它,因爲1位侵入符號位的位置。所以結果是0x8000_0000,這是一個負數 - INT_MIN準確。然後,它會看到您將該負數轉換爲64位,因此它將其擴展爲1,就像所有負數一樣。結果是0xffff_ffff_8000_0000,最小的32位有符號整數作爲有符號的64位整數存儲。

所有64位平臺的方式來做到這一點之間的正確和便攜是:

((size_t)1) << 32 
((size_t)1) << 31 
+2

另一個可愛的做法是唯一有用的通用結構:'sizeof(char)<< 31'。 –

5

0x1int類型和兩個表達式評估在具有32位int,一個實現:

0x1 << 32 

0x1 << 31 

調用未定義的行爲。

要解決此問題(但假設你不想讓zero對象評估到0),請在KarolS答案建議

(size_t) 1 << 32 

(size_t) 1 << 31 

這是假定size_t類型比32位更寬,這是在x64上執行clang時的情況。

+7

這是一個理由不這樣做,並且有原因的結果不出來的普通。這不是解釋這個具體價值是如何產生的,這也許是有用的。 – delnan

+0

假設32位'unsigned','size_t zero = 1U << 32;'和C11§6.5。7 3「如果右操作數的值爲負或大於或等於提升的左操作數的寬度,則行爲未定義。」暗示我的結果可能是'1'。 – chux

+0

@chux對,這是錯誤的。我修改了我的答案。 – ouah

相關問題