Specificatore di formato per caratteri non firmati

che voglio stampare unsigned char :

 unsigned char x = 12; 

che è corretto. Questo:

 printf("%d",x); 

o questo:

 printf("%u",x); 

?

La cosa è altrove su SO. Ho incontrato una discussione del genere:

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

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

Quindi quale è corretto? Qualche fonte affidabile dice su questo argomento? (In tal senso dovremmo anche stampare int unsigned short con% d perché può essere promosso a int ?).

Quello corretto è *:

 printf("%d",x); 

Questo perché le promozioni degli argomenti predefinite come printf() è la funzione variadic. Ciò significa che il valore unsigned char viene sempre promosso a int .

Da N1570 (bozza C11) 6.5.2.2/6 Chiamate di funzione (sottolineatura mia andando avanti):

Se l’espressione che denota la funzione chiamata ha un tipo che non include un prototipo, le promozioni intere vengono eseguite su ogni argomento e gli argomenti che hanno il tipo float vengono promossi a double . Queste sono chiamate promozioni di argomenti predefinite .

e il 6.5.2.2/7 dice:

La notazione di ellissi in un dichiaratore di prototipo di funzione causa l’interruzione della conversione del tipo di argomento dopo l’ultimo parametro dichiarato. Le promozioni degli argomenti predefiniti vengono eseguite sugli argomenti finali .

Queste promozioni intere sono definite in 6.3.1.1/2 Booleano, caratteri e numeri interi :

Se un int può rappresentare tutti i valori del tipo originale (come limitato dalla larghezza, per un campo di bit), il valore viene convertito in un int ; in caso contrario, viene convertito in un unsigned int . Queste sono chiamate promozioni intere .58) Tutti gli altri tipi sono invariati dalle promozioni intere.

Questa citazione risponde alla tua seconda domanda di unsigned short (vedi commento sotto).


* con eccezione di più di 8 bit di unsigned char (ad esempio potrebbe occupare 16 bit), vedere la risposta di @ chux.

Lo specificatore di formato corretto per unsigned char x = 12 dipende da un numero di cose:

Se INT_MAX >= UCHAR_MAX , che è spesso il caso, utilizzare "%d" . In questo caso, un unsigned char viene promosso a int .

 printf("%d",x); 

Altrimenti usa "%u" (o "%x" , "%o" ). In questo caso, un unsigned char viene promosso a unsigned .

 printf("%u",x); 

I compilatori aggiornati supportano il modificatore di lunghezza "hh" , che compensa questa ambiguità. Se x viene promosso a int o unsigned causa delle promozioni standard dei parametri variad, printf() converte in unsigned char prima della stampa.

 printf("%hhu",x); 

Se si ha a che fare con un vecchio compilatore senza "hh" o cercando codice altamente portatile, utilizzare il cast esplicito

 printf("%u", (unsigned) x); 

Lo stesso problema / risposta vale per unsigned short , prevedere INT_MAX >= USHRT_MAX e utilizzare "h" anziché "hh" .

Entrambi, unsigned char e unsigned short , possono sempre essere stampati in modo sicuro con %u . Le promozioni degli argomenti predefiniti le convertono in int o unsigned int . Se vengono promossi a quest’ultimo, tutto va bene (l’identificatore di formato e il tipo passato corrispondono), altrimenti C11 (n1570) 6.5.2.2 p6, primo punto, si applica:

  • un tipo promosso è un tipo intero con segno, l’altro tipo promosso è il corrispondente numero intero senza segno e il valore è rappresentabile in entrambi i tipi;

Lo standard è abbastanza chiaro che le promozioni degli argomenti predefiniti si applicano agli argomenti variadici di printf , ad esempio sono menzionate di nuovo per i modificatori di lunghezza hhhh (per lo più inutili) (ibid. 7.21.6.1 p7, emph.

hh – Specifica che un hh conversione seguente d , i , o , u , x o X applica a un signed char o a un argomento unsigned char ( l’argomento sarà promosso in base alle promozioni intere , ma il suo valore sarà convertito in signed char o unsigned char prima della stampa); […]

Per lo sviluppo multipiattaforma, in genere inttypes.h problema di promozione utilizzando inttypes.h

http://pubs.opengroup.org/onlinepubs/009695399/basedefs/inttypes.h.html

Questa intestazione (che è nello standard C99) definisce tutti i tipi di printf per i tipi di base. Quindi, se vuoi un uint8_t (una syntax che consiglio vivamente di usare al posto del char non firmato), userei

 #include  #include  uint8_t x; printf("%" PRIu8 "\n",x);