2012-09-19 96 views
7

我寫了下面的C代碼:ç十六進制常量類型

#include <stdio.h> 

int main() { 
    printf("%d\n", -1 >> 8); 
    return 0; 
} 

我編譯此代碼用gcc 4.6.3上使用-m32標誌我x86_64的。如我所料,我得到-1打印出來,這個移位發生在算術上使用2的補碼錶示,得到-1。現在

,如果我不是寫

printf("%d\n", 0xFFFFFFFF >> 8); 

我得到16777215我本來期望這個常量被解釋爲一個int(簽字),然後轉變爲算術,這將導致-1一次。我瀏覽了最新的C標準,似乎無法理解爲什麼會出現這種情況。有任何想法嗎?

+0

這是有符號(-1)和無符號(0xFFFFFFFF) – SpacedMonkey

+0

@SpacedMonkey之間的區別我在問爲什麼0xFFFFFFFF是無符號的 – dschatz

+0

@SpacedMonkey Btw,'-'沒有助於這種差異。 '-'仍然是一個一元運算符,並且不會做出簽名。它是帶符號的'1'(因此'-1'也被簽名),而'0xFFFFFFFF'是無符號的。 –

回答

10

根據C99標準(6.4.4.1),十六進制常數將是這個列表上的第一類型,它可以表示它們:

int 
unsigned int 
long int 
unsigned long int 
long long int 
unsigned long long int 

字面0xFFFFFFFF不會以int適應(它可以在十六進制將值-0x80000000保存爲0x7FFFFFFF),但確實適合於unsigned int,因此其類型將爲無符號。將無符號值0xFFFFFFFF右移8將得到16777215

+0

爲什麼0xFFFFFFFF不適合int? – dschatz

+0

@dschatz:因爲它是4294967295,你的'int'只能達到2147483647. –

+0

@dschatz:我剛剛編輯添加 - 因爲它大於0x7fffffff,它是32位int使用2的補碼錶示的最大值表示。 – interjay

10

未修飾積分文字具有不同的類型,這取決於它們是否是十進制或不(6.4.4.1/5在C11,表6在C++ 11):

  • 十進制文字,即[1-9][0-9]*,是始終簽名。

  • 十六進制和八進制文字有符號或無符號。如果該值對於有符號類型很大,但是足夠小以適應相同寬度的無符號類型,則該值將是無符號的。 (這是發生了什麼你的十六進制常量。)

向右移位負整數是實現定義的,而你碰巧得到符號擴展。右移無符號值是簡單的二分之一。

+0

我在這裏找到的C標準草案http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf顯示了十六進制常量在第64頁的unsigned int之前是ints。我錯過了什麼? – dschatz

+1

你所說的與C99標準(6.4.4.1/5)不符。根據這個十進制常數是有符號的,十六進制/八進制可以是有符號或無符號的。 – interjay

+1

@dschatz:哦,我弄錯了。讓我修復!在C++和C中的確如此。 –