2013-04-01 13 views

risposta

31

dichiarare il vostro ch come

unsigned char ch = 212 ; 

E il vostro printf funzionerà.

+9

Anche con 'ch' cambiato in' char' non firmato, il comportamento del codice non è definito dallo standard C. Questo perché il 'char unsigned 'è promosso a un' int' (nelle normali implementazioni C), quindi un 'int' viene passato a' printf' per lo specificatore '% u'. Tuttavia, '% u' si aspetta un' unsigned int', quindi i tipi non corrispondono, e lo standard C non definisce il comportamento. –

+2

Il tuo commento non è corretto. Lo standard C11 afferma che lo specificatore di conversione deve essere dello stesso tipo della funzione 'argument' stessa, non del tipo promosso. Questo punto è anche affrontato in modo specifico nella descrizione del modificatore di lunghezza 'hh': " l'argomento sarà promosso in base alle promozioni intere, ma il suo valore sarà convertito in char con segno o senza segno prima di stampare " –

+0

Solo lavorato dopo il cast esplicito a 'unsigned int' quando viene passato a' prtinf() '. L'aggiunta di -std = c11 al comando gcc-4.8.4 per applicare lo standard non ha avuto alcun effetto. – ypx

28

Questo perché in questo caso il tipo char è firmato sul sistema *. Quando ciò accade, i dati vengono estesi dal segno durante le conversioni predefinite mentre si passano i dati alla funzione con un numero variabile di argomenti. Dal momento che 212 è maggiore di 0x80, è trattata come negativo, %u interpreta il numero come un gran numero positivo:

212 = 0xD4 

Quando è segno-esteso, FF s sono pre-pended al vostro numero, in modo che diventi

0xFFFFFFD4 = 4294967252 

che è il numero che viene stampato.

Si noti che questo comportamento è specifico per l'implementazione. In base alle specifiche C99, tutti i tipi char vengono promossi a (firmato) int, perché un int può rappresentare tutti i valori di un char, con o senza segno:

6.1.1.2: Se un int può rappresentare tutti i valori della tipo originale, il valore viene convertito in int; in caso contrario, viene convertito in unsigned int.

Ciò provoca passaggio di un int un formato specificatore %u, che prevede un unsigned int.

Per evitare un comportamento indefinito nel programma, aggiungere il tipo esplicito getta come segue:

unsigned char ch = (unsigned char)212; 
printf("%u", (unsigned int)ch); 


* In generale, lo standard lascia la signedness di char fino alla realizzazione. Vedi this question per maggiori dettagli.

+1

Questa risposta è confusa e imprecisa.Le frasi sull'estensione del segno e sul trattamento 212 sono presentate senza contesto, senza riuscire a spiegare dove si applicano (la frase precedente si applica a un'operazione successiva, la promozione intera del 'char' quando viene usata come argomento, mentre la frase successiva si applica a una precedente operazione, inizializzazione del 'char' con un' int'). –

+1

L'affermazione che 212 è considerata negativa perché è maggiore di 0x80 è falsa. Innanzitutto, l'inizializzazione di un 'char' firmato con 212 causa l'overflow dei numeri interi nella maggior parte delle implementazioni C, quindi il comportamento non è definito. In molte implementazioni C, ciò comporta il troncamento della rappresentazione del complemento a due da 212 a 8 bit, il che fa interpretare i bit come un valore negativo perché il bit 0x80 è impostato, non perché il valore iniziale è maggiore di 0x80 (i controesempi includono 0x80 e 0x100). –

+1

Dopo l'inizializzazione di 'char', viene usato come argomento per' printf'. Le promozioni intere vengono eseguite, risultando in un 'int' negativo passato a' printf'. Ancora una volta, molte implementazioni C usano il complemento a due, quindi viene eseguita un'estensione del segno, come dice questa risposta. Convertire il valore in 'unsigned' a questo punto produrrebbe un grande numero positivo. Tuttavia, questa risposta non riesce a spiegare che il comportamento effettivo non è definito dallo standard C poiché viene passato un 'int' per un identificatore di'% u', che si aspetta un 'int unsigned '. –

2

L'intervallo di caratteri è compreso tra 127 e -128. Se assegni 212, ch memorizza -44 (212-128-128) non 212.Quindi se provi a stampare un numero negativo come non firmato ottieni (valore MAX di unsigned int) -abs (numero) che in questo caso è 4.294.967,252 mila

Quindi, se si desidera memorizzare 212 come è nel ch l'unica cosa che si può fare è dichiarare ch come

unsigned char ch; 

ora la gamma di ch va da 0 a 255.

+2

"L'intervallo di caratteri è compreso tra 127 e -128." - No, l'intervallo è definito dall'implementazione. –

+0

@Jim Cosa intendi? – banarun

+1

Intendo quello che ho detto ... era molto chiaro. Un char non è nemmeno necessariamente 8 bit, lasciati necessariamente firmati. –

9

Ci sono due errori in questo codice. Innanzitutto, nella maggior parte delle implementazioni C con firma char, c'è un overflow in char ch = 212 perché 212 non si adatta a un 82 bit firmato char e lo standard C non definisce il comportamento quando c'è un numero intero di overflow. Dovrebbe essere invece:

unsigned char ch = 212; 

In secondo luogo, in printf("%u",ch), ch sarà promosso a un int nelle normali implementazioni C. Tuttavia, lo specificatore %u prevede uno unsigned int e lo standard C non definisce il comportamento quando viene passato il tipo errato. Dovrebbe essere invece:

printf("%u", (unsigned) ch); 
+0

Vorrei suggerire di usare static_cast invece del cast vecchio stile – ShitalShah

+1

@ShitalShah: La domanda è codificata con C, non C++. C non ha un operatore static_cast. –

+0

Ah .. non l'ho visto. – ShitalShah

1

Perché char è di default signed dichiarato che significa che la gamma della variabile è

-127 a +127>

il tuo valore è traboccato. Per ottenere il valore desiderato devi dichiarare il modificatore unsigned. (unsigned) la gamma del modificatore è:

0 to 255 

per ottenere la gamma di qualsiasi tipo di dati seguire il processo 2^bit esempio char è 8 bit di lunghezza per ottenere la sua gamma solo 2 ^(power) 8.

1

Nel caso in cui non si può modificare la dichiarazione per qualsiasi motivo, si può fare:

char ch = 212; 
printf("%d", (unsigned char) ch); 
Problemi correlati