Come devo stampare tipi come off_t e size_t?


148

Sto cercando di stampare tipi come off_te size_t. Qual è il segnaposto corretto per printf() questo è portatile ?

O c'è un modo completamente diverso di stampare quelle variabili?


2
@devin: Credo di aver trovato quel tipo durante l'utilizzo fopen, fseekecc su Mac OS X. off_tviene utilizzato per l'offset.
Georg Schölly,

Risposte:


112

Puoi usare zper size_t e tper ptrdiff_t come in

printf("%zu %td", size, ptrdiff);

Ma la mia manpage dice che alcune biblioteche più vecchie usavano un personaggio diverso da quello ze ne scoraggia l'uso. Tuttavia, è standardizzato (dallo standard C99). Per chi intmax_te int8_tdi stdint.h, e così via, ci sono le macro è possibile utilizzare, come un'altra risposta ha detto:

printf("value: %" PRId32, some_int32_t);
printf("value: %" PRIu16, some_uint16_t);

Sono elencati nella manpage di inttypes.h.

Personalmente, vorrei solo lanciare i valori unsigned longo longcome consiglia un'altra risposta. Se usi C99, puoi (e ovviamente, ovviamente) eseguire il cast verso unsigned long longo long longe utilizzare rispettivamente i formati %lluo %lld.


2
off_t è in realtà un long long firmato sul mio sistema.
Georg Schölly,

2
Penso che la pagina man scoraggi l'uso di Z (maiuscolo) che è stato usato da libc5. Non sembra scoraggiare z (minuscolo).
Draemon,

12
L'uso %zdcon a nonsize_t è un comportamento definito a causa della mancata corrispondenza della firma (C99 7.19.6.1 # 9). Deve essere %zu.
Jens

7
Bene, come stampare off_t allora?
JohnyTex,

3
@Jens Non vedo come %zdcon un size_tcomportamento indefinito si ottenga da quel paragrafo o da qualsiasi altro. In effetti, la definizione di %zin # 7 consente esplicitamente %dcon size_te il tipo con segno corrispondente e §6.2.5 # 9 consente esplicitamente l'uso di valori di tipi senza segno in cui è previsto il tipo con segno corrispondente, purché il valore sia un valore non negativo valido del tipo firmato.
Chortos-2

108

Per stampare off_t:

printf("%jd\n", (intmax_t)x);

Per stampare size_t:

printf("%zu\n", x);

Per stampare ssize_t:

printf("%zd\n", x);

Vedi 7.19.6.1/7 nello standard C99 o la documentazione POSIX più conveniente dei codici di formattazione:

http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html

Se la tua implementazione non supporta quei codici di formattazione (ad esempio perché sei su C89), allora hai un po 'di problemi dal momento che AFAIK non ci sono tipi interi in C89 che hanno codici di formattazione e sono garantiti per essere grandi come questi tipi. Quindi devi fare qualcosa di specifico per l'implementazione.

Ad esempio se il tuo compilatore ha long longe la tua libreria standard supporta %lld, puoi aspettarti con sicurezza che servirà al posto di intmax_t. In caso contrario, dovrai ricorrere a long, il che fallirebbe su alcune altre implementazioni perché è troppo piccolo.


3
Questa è di gran lunga la risposta migliore, mi sarei dimenticato di usare% zu per unsigned size_t. E il casting su intmax_t è un'ottima soluzione a qualunque off_t sia su qualsiasi piattaforma.
Peter Cordes,

2
POSIX non garantisce che ssize_tabbia le stesse dimensioni di size_t, quindi il codice veramente portatile dovrebbe convertirlo intmax_te stamparlo %jdcome off_t.
nwellnhof,

off_t può avere dimensioni molto lunghe e può essere variabile a seconda di quanto definito ... Visual Studio lo avverte anche con questo "avviso C4477: '_snprintf_s': la stringa di formato '% jd' richiede un argomento di tipo '__int64', ma argomento variadico 1 ha il tipo 'off_t' "... Un modo veramente portatile è printf ("% lld \ n ", (long long) x);
Ericcurtin,

5

Per Microsoft, la risposta è diversa. VS2013 è ampiamente conforme a C99 ma "[t] he hh, j, z e prefissi di lunghezza non sono supportati." Per size_t "ovvero __int32 senza segno su piattaforme a 32 bit, __int64 senza segno su piattaforme a 64 bit" utilizzare il prefisso I (occhio di capitale) con l' identificatore di tipo o, u, x o X. Vedere le specifiche di dimensione VS2013

Per quanto riguarda off_t, è definito come lungo in VC \ include \ sys \ types.h.


Nota se off_tè sempre longquello lo renderebbe a 32 bit (anche Windows a 64 bit utilizza 32 bit per long).
sourcejedi,

3

Quale versione di C stai usando?

In C90, la pratica standard consiste nel lanciare a lungo firmato o non firmato, come appropriato, e stampare di conseguenza. Ho visto% z per size_t, ma Harbison e Steele non lo menzionano sotto printf (), e in ogni caso ciò non ti aiuterebbe con ptrdiff_t o altro.

In C99, i vari tipi di _t vengono forniti con le loro macro printf, quindi qualcosa come "Size is " FOO " bytes." io non conosco i dettagli, ma fa parte di un formato numerico abbastanza grande che include file.


3

Ti consigliamo di utilizzare le macro di formattazione da inttypes.h.

Vedi questa domanda: stringa di formato multipiattaforma per variabili di tipo size_t?


Supponendo che off_t sia un int con dimensioni di puntatore (non so quale sia la definizione precisa) come ptrdiff_t, allora useresti PRIdPTR o PRIiPTR.
Michael Burr,

11
Il off_ttipo è più grande di un puntatore su qualsiasi sistema a 32 bit che supporta file di grandi dimensioni (che è la maggior parte dei sistemi a 32 bit in questi giorni).
Dietrich Epp,

1
@DietrichEpp: In realtà, è peggio di così; molti sistemi a 32 bit hanno sia off_t che off64_t e, a seconda della macro delle funzioni, off_t può effettivamente significare off64_t.
SamB

1

Guardando man 3 printfsu Linux, OS X e OpenBSD tutti mostrano il supporto %zper size_te %tper ptrdiff_t(per C99), ma nessuno di questi menziona off_t. I suggerimenti in natura offrono solitamente la %uconversione per off_t, che è "abbastanza corretta" per quanto ne so (entrambi unsigned inte off_tvariano in modo identico tra i sistemi a 64 e 32 bit).


1
Il mio sistema (OS X) ha 32 bit unsigned inte 64 bit off_t. Quindi il cast causerebbe la perdita di dati.
Dietrich Epp,

-3

Ho visto questo post almeno due volte, perché la risposta accettata è difficile da ricordare per me (uso raramente zo jflag e non sembrano indipendenti dalla piattaforma ).

Lo standard non dice mai chiaramente la lunghezza esatta dei dati size_t, quindi ti consiglio di controllare prima la lunghezza size_tsulla tua piattaforma, quindi selezionarne una:

if sizeof(size_t) == 4 use PRIu32
if sizeof(size_t) == 8 use PRIu64

E suggerisco di usare stdinttipi invece di tipi di dati grezzi per coerenza.


1
Per C99 e C11, lo standard afferma esplicitamente che %zupuò essere utilizzato per stampare size_tvalori. Non si dovrebbe assolutamente ricorrere all'uso di un identificatore uint32_t/ uint64_tformat per stampare un size_t, in quanto non esiste alcuna garanzia che tali tipi siano compatibili.
Autistico

-4

Per quanto ricordo, l'unico modo portatile per farlo è quello di trasmettere il risultato a "unsigned long int" e usarlo %lu.

printf("sizeof(int) = %lu", (unsigned long) sizeof(int));

1
Dovrebbe essere "% lu", poiché il modificatore di lunghezza dovrebbe arrivare prima della conversione.
dwc,

1
off_t ad esempio è un long long firmato.
Georg Schölly,

@ GeorgSchölly - Quindi hai colpito un enigma, perché long longnon esiste nello standard C ++ ed è quindi intrinsecamente non portatile.
James Curran,

-9

usa "% zo" per off_t. (ottale) o "% zu" per i decimali.


Perché dovresti volere il file offset in ottale?
poolie
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.