2012-09-19 14 views
7

ho scritto il seguente codice C:C esadecimale costante tipo

#include <stdio.h> 

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

compilo questo codice con gcc 4.6.3 sul mio x86_64 utilizzando il flag -m32. Ottengo -1 stampato come mi aspetterei, lo spostamento avviene aritmeticamente usando la rappresentazione del complemento a due risultante in -1.

Ora se invece scrivo

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

ottengo 16777215. avrei aspettato questa costante deve essere interpretato come un int (firmato) e quindi il passaggio di essere aritmetica che porterebbe a -1 nuovamente. Ho esaminato l'ultimo standard C e non riesco a capire perché questo sia il caso. Qualche idea?

+0

È la differenza tra firmato (-1) e non firmato (0xFFFFFFFF) – SpacedMonkey

+0

@SpacedMonkey Sto chiedendo perché 0xFFFFFFFF è senza firma – dschatz

+0

@SpacedMonkey Btw, '-' non contribuisce a questa differenza. '-' è ancora un operatore unario e non fa firmare qualcosa. È '1' che è firmato (e quindi anche' -1' è firmato), mentre '0xFFFFFFFF' non è firmato. –

risposta

10

Secondo lo standard C99 (6.4.4.1), costanti esadecimali sarà il primo tipo in questo elenco che possono rappresentare:

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

L'esagono letterale 0xFFFFFFFF non adattarsi in un int (che può tenere i valori -0x80000000 a 0x7FFFFFFF), ma si adatta a unsigned int e pertanto il suo tipo sarà senza segno. Spostando a destra il valore senza segno 0xFFFFFFFF con 8 si ottiene 16777215.

+0

Perché 0xFFFFFFFF non si inserisce in un int? – dschatz

+0

@dschatz: Perché è 4294967295 e il tuo 'int' può arrivare solo a 2147483647. –

+0

@dschatz: Ho appena modificato per aggiungere - Perché è più di 0x7fffffff che è il valore più grande rappresentabile da un int a 32 bit utilizzando il complemento a 2 rappresentazione. – interjay

10

letterali integrali Undecorated hanno diverso tipo a seconda che siano o meno decimale (6.4.4.1/5 a C11, tabella 6 C++ 11):

  • letterali decimali, cioè [1-9][0-9]*, sono sempre firmato

  • letterali esadecimali e ottali sono firmati o non firmati. Se il valore è troppo grande per un tipo con segno, ma abbastanza piccolo per adattarsi al tipo senza segno della stessa larghezza, non sarà firmato. (Questo è ciò che accade alla vostra costante esadecimale.)

destro spostando interi negativi è definito dall'implementazione, e vi capita di avere estensione del segno. Spostando a destra il valore senza segno è semplice divisione per due.

+0

La bozza standard C che ho trovato qui http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf mostra che le costanti esadecimali sono int prima di uns non firmati a pagina 64. Cosa mi manca ? – dschatz

+1

Quello che hai detto non corrisponde allo standard C99 (6.4.4.1/5). Secondo tale costante decimale sono firmate e hex/octal può essere firmato o non firmato. – interjay

+1

@dschatz: Oh, ho capito male. Lasciami aggiustare! È lo stesso in C++ e C. –