2012-09-19 16 views
7

Napisałem następujący kod c:C hex stały typ

#include <stdio.h> 

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

skompilować ten kod z gcc 4.6.3 na moim x86_64 używając -m32 flagę. Otrzymuję -1 wydrukowane, jak można by się spodziewać, przesunięcie następuje arytmetycznie za pomocą dwójki uzupełnień reprezentujących -1.

Teraz gdybym zamiast pisać

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

uzyskać 16777215. Liczyłam tej stałej należy interpretować jako int (podpisany), a następnie przesunięcie się arytmetyka co skutkowałoby -1 ponownie. Przejrzałem najnowszy standard C i nie mogę zrozumieć, dlaczego tak się dzieje. Jakieś pomysły?

+0

Jest to różnica między podpisane (-1) i bez znaku (0xFFFFFFFF) – SpacedMonkey

+0

@SpacedMonkey pytam dlaczego 0xFFFFFFFF jest niepodpisany – dschatz

+0

@SpacedMonkey Btw, '-' nie przyczynia się do tej różnicy. '-' jest nadal operatorem jednoargumentowym i nie powoduje podpisu. To jest '1', które jest podpisane (i dlatego też jest podpisane' -1'), podczas gdy '0xFFFFFFFF' jest unsigned. –

Odpowiedz

10

Według standardu C99 (6.4.4.1), Stałe szesnastkowe będzie pierwszy typ na tej liście, które mogą je reprezentować:

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

Heks dosłowne 0xFFFFFFFF nie pasuje w int (co może trzymaj wartości -0x80000000 do 0x7FFFFFFF), ale zmieści się w unsigned int, a zatem jego typ będzie niepodpisany. Przesunięcie w prawo niepodpisanej wartości 0xFFFFFFFF o 8 daje 16777215.

+0

Dlaczego nie 0xFFFFFFFF pasuje do int? – dschatz

+0

@dschatz: Ponieważ jest to 4294967295, a twoje 'int' może wzrosnąć tylko do 2147483647. –

+0

@dschatz: Właśnie edytowałem, aby dodać - Ponieważ jest to więcej niż 0x7fffffff, który jest największą wartością reprezentowaną przez 32-bitową int, używając dopełnienia 2 reprezentacja. – interjay

10

undecorated integralne literałami mają różny typ zależności od tego czy są one czy nie dziesiętny (6.4.4.1/5 w C11 Tabela 6 C++ 11):

  • literały dziesiętnych, tj [1-9][0-9]* są zawsze podpisany.

  • Literały szesnastkowe i ósemkowe są podpisane lub niepodpisane. Jeśli wartość jest duża dla typu podpisanego, ale wystarczająco mała, aby zmieścić typ bez znaku o tej samej szerokości, będzie niepodpisana. (To jest to, co dzieje się stałą hex.)

prawym przesunięcie ujemne liczby całkowite wdrożenie jest zdefiniowane i zdarzy ci się dostać logowania rozszerzenie. Przesunięcie prawej wartości bez znaku jest proste dzielenie przez dwa.

+0

Standardowy projekt C, który znalazłem tutaj http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf pokazuje, że stałe heksadecymalne są ints przed unsigned ints na stronie 64. Czego mi brakuje ? – dschatz

+1

To, co powiedziałeś, nie pasuje do standardu C99 (6.4.4.1/5). Zgodnie z tymi dziesiętnymi stałymi są podpisane, a szesnastkowe/ósemkowe mogą być podpisane lub niepodpisane. – interjay

+1

@dschatz: Oh, źle to zrozumiałem. Pozwól mi naprawić! Tak samo jest w C++ i C. –