printf-Formatbezeichner für uint32_t und size_t

101

Ich habe folgendes

size_t   i = 0;
uint32_t k = 0;

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

Beim Kompilieren wird folgende Warnung angezeigt:

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

Als ich dies mit einer Schiene ausführte, bekam ich Folgendes:

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

Vielen Dank für jeden Rat,

ant2009
quelle
2
C89 unterstützt nicht uint32_tvon <stdint.h>oder <inttypes.h>; Wenn Sie diese Typen verwenden möchten, sollten Sie ein Upgrade auf C89 durchführen. Als Erweiterung ist es wahrscheinlich, dass GCC Ihnen die Verwendung erlaubt, aber C89 hatte keine solche Unterstützung.
Jonathan Leffler
10
Und der offizielle C99-Formatmodifikator für size_tist 'z', wie in "%zu".
Jonathan Leffler
1
stackoverflow.com/questions/1401526/…
Ciro Santilli 法轮功 冠状 冠状 六四 六四 法轮功
Ich glaube, @ Kennys Antwort ist am besten für uint32_t, aber es fehlt size_t. Die Antwort von @ u0b34a0f6ae beinhaltet beides.
JWW
Die zweite Erwähnung von C89 im ersten Kommentar von Jonathan Leffler sollte C99 sein
bph

Antworten:

28

Klingt so, als würden Sie erwarten size_t, dass es dasselbe ist wie unsigned long(möglicherweise 64 Bit), wenn es tatsächlich ein unsigned int(32 Bit) ist. Versuchen Sie es %zuin beiden Fällen.

Ich bin mir allerdings nicht ganz sicher.

Zahnrad
quelle
1
Keine Warnungen beim Kompilieren. Beim Ausführen von splint erhalte ich jedoch Folgendes: 1) printf (% u) erwartet, dass int ohne Vorzeichen uint32_t erhält: i 2) printf (% u) erwartet, dass int ohne Vorzeichen size_t erhält: k
ant2009
Klingt so, als wäre die Schiene nur pedantisch. Es geht wahrscheinlich um die Namen der Typen im Quellcode und merkt nicht, dass sie gleichwertig sind. Ich frage mich, was es mit der Antwort von @ KennyTM machen würde ... Es sollte auf jeden Fall portabler sein.
Zahnrad
3
Schiene macht eigentlich das Richtige. Nur weil es sich int32_tzufällig intauf Ihrem Compiler / Ihrer Plattform befindet, heißt das nicht, dass es sich möglicherweise nicht longauf einem anderen befindet. Gleiches gilt für size_t. Es ist wirklich sehr anstrengend und macht mehr Arbeit, um diesen Portabilitätsfehler zu erkennen, da die einfache, natürliche Überprüfung darin besteht, nur den Typedef zu ehren, wie es der Compiler tut.
R .. GitHub STOP HELPING ICE
4
-1, tut mir leid, es ist nicht portabel. Alles, was benötigt wird, ist, dass die Formatspezifizierer und die Typen übereinstimmen, und Sie können jederzeit umwandeln, um dies zu erreichen. lang ist mindestens 32bit, also ist %luzusammen mit (unsigned long)kimmer richtig. size_tist schwieriger, weshalb %zuin C99 hinzugefügt wurde. Wenn Sie das nicht verwenden können, behandeln Sie es genauso k( longist der größte Typ in C89, es size_tist sehr unwahrscheinlich, dass er größer ist).
u0b34a0f6ae
139

Versuchen

#include <inttypes.h>
...

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

Das zstellt eine Ganzzahl mit der gleichen Länge dar wie size_t, und das im C99-Header definiertePRIu32 Makro repräsentiert eine vorzeichenlose 32-Bit-Ganzzahl.inttypes.h

kennytm
quelle
3
@robUK: Heh. Ich schlage vor, Sie melden einen Fehler für die Schiene.
Kennytm
8
Das ist die richtige Antwort. Obwohl meine persönliche Empfehlung ist, einfach zu besetzen, z printf( "%lu", (unsigned long )i ). Andernfalls kommt es später aufgrund einer Typänderung zu einer Reihe von Warnungen im gesamten Code.
Dummy00001
1
Dies ist die richtige Antwort. Ich stimme KennyTM darin zu, einen Fehler für die Schiene einzureichen. "% Zu" ist übrigens das richtige Format für size_t. Sie benötigen keines der PRI * -Makros zum Drucken von size_t.
R .. GitHub STOP HELPING ICE
1
Wenn ich mich richtig erinnere, ist% zu C99, und in der Frage schrieb er 'C89'.
Alcor
8
@alcor Ja, er hat C89 gesetzt (anscheinend das von ihm verwendete gcc-Compiler-Flag), aber er verwendet es, uint32_talso ist es tatsächlich C99-Code und sollte als solches kompiliert werden.
Colin D Bennett
28

Alles, was benötigt wird, ist, dass die Formatspezifizierer und die Typen übereinstimmen, und Sie können jederzeit umwandeln, um dies zu erreichen. longist mindestens 32 Bit, also %luzusammen mit (unsigned long)kist immer richtig:

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

size_tist schwieriger, weshalb %zuin C99 hinzugefügt wurde. Wenn Sie das nicht verwenden können, behandeln Sie es genauso k( longist der größte Typ in C89, es size_tist sehr unwahrscheinlich, dass er größer ist).

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

Wenn Sie die Formatspezifizierer für den übergebenen Typ nicht korrekt erhalten, printfentspricht dies dem Lesen von zu viel oder zu wenig Speicher aus dem Array. Solange Sie explizite Casts verwenden, um Typen abzugleichen, ist es portabel.

u0b34a0f6ae
quelle
17

Wenn Sie nicht über die PRI * Makros verwenden möchten, ein weiterer Ansatz für das Drucken ANY Typ integer ist cast intmax_toder uintmax_tund Verwendung "%jd"oder %jusind. Dies ist besonders nützlich für POSIX-Typen (oder andere Betriebssystemtypen), für die beispielsweise keine PRI * -Makros definiert sind off_t.

R .. GitHub HÖREN SIE AUF, EIS ZU HELFEN
quelle