2014-07-10 4 views
8

Sto provando a fare un test per dire se il mio PC esegue il giusto spostamento aritmetico o logico spostando a destra il numero esadecimale FFFFFFFF entro il 1.Perché -1 >> 1 e 0xFFFFFFFF >> 1 producono risultati diversi?

So che un numero intero -1 si legge come FFFFFFFF in esadecimale poiché è il complemento a due di 1. Lo spostamento a destra di -1 entro il 1 produce FFFFFFFF e mostra che il PC ha eseguito il giusto spostamento aritmetico.

Ma se si digita semplicemente 0xFFFFFFFF >> 1, risulta 7FFFFFFF e indica che il PC ha eseguito il giusto spostamento logico. Perché è successo? Vedere per il codice qui sotto che ha prodotto i risultati:

#include <stdlib.h> 
#include <stdio.h> 

int main (int argc, char *argv[]) 
{ 
    printf ("%x >> 1 = %x\n", -1, -1 >> 1); 
    printf ("%x >> 1 = %x\n", 0xffffffff, 0xffffffff >> 1); 

    return EXIT_SUCCESS; 
} 

uscita del programma è stata:

ffffffff >> 1 = ffffffff 
ffffffff >> 1 = 7fffffff 
+3

'-1' è firmato. '0xffffffff' non è firmato. Non ha nulla a che fare con 'printf()'. – chux

+0

I valori con segno negativo a spostamento a destra sono definiti dall'implementazione: '-1 >> 1' potrebbe stampare anche come' 7fffffff'. – chqrlie

risposta

7

Non è un'ipotesi. Cosa tipo pensi che 0xffffffff è? Secondo lo standard C, 6.4.4.1 costanti intere, il tipo dell'espressione di un esadecimale costante (preceduto 0x) è il primo dei seguenti elementi possono applicably contenere il valore rappresentato:

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

Sulla piattaforma, 0xFFFFFFFF non può essere rappresentato come int perché int è di 32 bit e solo 31 bit di quantità espressa in signed int (lo standard stabilisce che un bit è riservato per il segno). Viene quindi utilizzato il tipo successivo, unsigned int. Pertanto non è presente alcun bit di segno esteso con l'operazione di shift, che è quindi logica piuttosto che aritmetica.

Potrebbe non essere chiaro come ho concluso che lo int era 32 bit sulla piattaforma. Effettivamente non ho potuto fare quella supposizione se non fosse stato per la prima riga , che aritmetica-destra sposta il valore di -1. Il risultato di questo turno, scaricato come %x, era 0xFFFFFFFF. Aveva int nativo 64-bit che dovrebbe scaricare 0xFFFFFFFFFFFFFFFF invece. Senza tale conoscenza preliminare, non si può assumere nessuna conclusione di tipo singolo di 0xFFFFFFFF poiché potrebbe essere rappresentabile come standard firmato int di larghezza 64-bit (63 + 1) con valore 0x00000000FFFFFFFF.Lo spostamento risultante produrrebbe lo stesso risultato che si vede ora, introducendo così un'alternativa a quella postulata sopra.

6

La sua domanda principale è: è 0xffffffff unsigned?

Da C11 §6.4.4.1 costanti intere

Il tipo di un numero intero costante è la prima della lista corrispondente in cui il suo valore può essere rappresentato .

enter image description here

L'uscita della prima linea printf suggerisce che int è 32 bit sul computer. Quindi non può rappresentare 0xffffffff, deve essere senza segno.

+0

Non c'è niente in questo grafico che porta 0xffffffff è 'unsigned'. È il '-1 di OP che guida la conclusione. – chux

+0

@chux Ho capito il tuo punto e hai ragione. Ma non penso che quando OP chiede se si tratta di un intero senza segno, intende il tipo 'unsigned' (cioè,' unsigned int') esattamente. Penso che intenda i tipi non firmati in generale, cioè "unsigned int", "unsigned long" o "unsigned long long". Ecco perché non ho usato il formato di codice * 'unsigned' *, only * unsigned *. –

+0

'0xffffffff' potrebbe essere' int' (aka 'signed int') dovrebbe' int' essere 64-bit. Dato lo spec. C '0xffffffff' deve essere' int', 'unsigned int',' long int' o 'unsigned long int'. – chux