specificatori di formato printf per uint32_t e size_t


101

Ho il seguente

size_t   i = 0;
uint32_t k = 0;

printf("i [ %lu ] k [ %u ]\n", i, k);

Ricevo il seguente avviso durante la compilazione:

format ‘%lu expects type long unsigned int’, but argument has type uint32_t

Quando l'ho eseguito utilizzando splint ho ottenuto quanto segue:

Format argument 1 to printf (%u) expects unsigned int gets size_t: k

Molte grazie per qualsiasi consiglio,


2
C89 non supporta uint32_tda <stdint.h>o <inttypes.h>; se vuoi usare questi tipi, dovresti aggiornare a C89. Come estensione, è probabile che GCC ti consenta di usarli, ma C89 non aveva tale supporto.
Jonathan Leffler

10
E il modificatore di formato C99 ufficiale per size_tè "z", come in "%zu".
Jonathan Leffler


Credo che la risposta di @ kenny sia la migliore per uint32_t, ma manca size_t. La risposta di @ u0b34a0f6ae include entrambi.
jww

La seconda menzione di C89 nel primo commento di Jonathan Leffler dovrebbe essere C99
bph

Risposte:


28

Sembra che ti aspetti size_tdi essere lo stesso di unsigned long(forse 64 bit) quando in realtà è un unsigned int(32 bit). Prova a utilizzare %zuin entrambi i casi.

Non sono del tutto certo però.


1
Nessun avviso durante la compilazione. Tuttavia, eseguendo splint ottengo quanto segue: 1) printf (% u) si aspetta che unsigned int riceva uint32_t: i 2) printf (% u) si aspetta che unsigned int ottenga size_t: k
ant2009

Allora sembra che splint sia solo pedante. Probabilmente sta cancellando i nomi dei tipi nel codice sorgente e non si rende conto che sono equivalenti. Mi chiedo cosa farebbe con la risposta di @ KennyTM ... Certamente dovrebbe essere più portatile.
Ruota dentata

3
splint sta effettivamente facendo la cosa giusta. Solo perché int32_tsembra essere intsul tuo compilatore / piattaforma non significa che potrebbe non essere longsu un altro. Lo stesso per size_t. In realtà sta facendo di tutto e sta facendo più lavoro per rilevare questo bug di portabilità poiché il controllo facile e naturale sarebbe quello di onorare il typedef come fa il compilatore.
R .. GitHub SMETTA DI AIUTARE IL GHIACCIO

4
-1, mi dispiace non è portatile. Tutto ciò che serve è che gli specificatori di formato ei tipi siano d'accordo e puoi sempre eseguire il cast per renderlo vero. long è di almeno 32 bit, quindi %luinsieme a (unsigned long)kè sempre corretto. size_tè più complicato, motivo per cui è %zustato aggiunto in C99. Se non puoi usarlo, trattalo come k( longè il tipo più grande in C89, size_tè molto improbabile che sia più grande).
u0b34a0f6ae

139

Provare

#include <inttypes.h>
...

printf("i [ %zu ] k [ %"PRIu32" ]\n", i, k);

Il zrappresenta un numero intero di lunghezza uguale a size_te la PRIu32macro, definita nell'intestazione C99inttypes.h , rappresenta un numero intero a 32 bit senza segno.


3
@robUK: Heh. Ti suggerisco di segnalare un bug per splint.
kennytm

8
Questa è la risposta esatta. Anche se la mia raccomandazione personale è semplicemente di lanciare, ad es printf( "%lu", (unsigned long )i ). Altrimenti si finisce più tardi con una pila di avvisi in tutto il codice a causa di un cambio di tipo.
Dummy00001

1
Questa è la risposta corretta. Sono d'accordo con KennyTM sulla presentazione di un bug per splint. A proposito, "% zu" è il formato corretto per size_t. Non hai bisogno di nessuna delle macro PRI * per stampare size_t.
R .. GitHub SMETTA DI AIUTARE IL GHIACCIO

1
Se ricordo bene% zu è C99 e nella domanda ha scritto "C89".
alcor

8
@alcor sì, ha messo C89 (apparentemente il flag del compilatore gcc che sta usando) ma sta usando uint32_tquindi in realtà è codice C99 e dovrebbe essere compilato come tale.
Colin D Bennett

28

Tutto ciò che serve è che gli specificatori di formato ei tipi siano d'accordo e puoi sempre eseguire il cast per renderlo vero. longè di almeno 32 bit, quindi %luinsieme a (unsigned long)kè sempre corretto:

uint32_t k;
printf("%lu\n", (unsigned long)k);

size_tè più complicato, motivo per cui è %zustato aggiunto in C99. Se non puoi usarlo, trattalo come k( longè il tipo più grande in C89, size_tè molto improbabile che sia più grande).

size_t sz;
printf("%zu\n", sz);  /* C99 version */
printf("%lu\n", (unsigned long)sz);  /* common C89 version */

Se non ottieni gli specificatori di formato corretti per il tipo che stai passando, allora printffarà l'equivalente di leggere troppa o troppo poca memoria dall'array. Finché usi cast espliciti per abbinare i tipi, è portatile.


17

Se non si desidera utilizzare le macro PRI *, un altro approccio per la stampa di QUALSIASI tipo intero consiste nel eseguire il cast a intmax_to uintmax_te utilizzare "%jd"o %ju, rispettivamente. Ciò è particolarmente utile per i tipi POSIX (o altri sistemi operativi) che non hanno macro PRI * definite, ad esempio off_t.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.