spécificateurs de format printf pour uint32_t et size_t

101

J'ai ce qui suit

size_t   i = 0;
uint32_t k = 0;

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

J'obtiens l'avertissement suivant lors de la compilation:

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

Quand j'ai exécuté ceci en utilisant une attelle, j'ai obtenu ce qui suit:

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

Merci beaucoup pour tout conseil,

ant2009
la source
2
C89 ne prend pas en charge uint32_tde <stdint.h>ou <inttypes.h>; si vous souhaitez utiliser ces types, vous devez mettre à niveau vers C89. En tant qu'extension, il est probable que GCC vous autorise à les utiliser, mais C89 ne disposait pas d'un tel support.
Jonathan Leffler
10
Et le modificateur de format officiel C99 pour size_test «z», comme dans "%zu".
Jonathan Leffler
1
stackoverflow.com/questions/1401526/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Je crois que la réponse de @ kenny est la meilleure pour uint32_t, mais elle manque size_t. La réponse de @ u0b34a0f6ae comprend les deux.
jww
2ème mention de C89 dans le 1er commentaire de Jonathan Leffler devrait être C99
bph

Réponses:

28

On dirait que vous vous attendez size_tà être le même que unsigned long(peut-être 64 bits) alors qu'il s'agit en fait d'un unsigned int(32 bits). Essayez d'utiliser %zudans les deux cas.

Je ne suis pas tout à fait sûr cependant.

Roue dentée
la source
1
Aucun avertissement lors de la compilation. Cependant, en exécutant splint, j'obtiens ce qui suit: 1) printf (% u) attend un int non signé obtient uint32_t: i 2) printf (% u) attend un int non signé obtient size_t: k
ant2009
On dirait que l'attelle est juste pédante, alors. Cela va probablement sur les noms des types dans le code source et ne se rend pas compte qu'ils sont équivalents. Je me demande ce que cela ferait avec la réponse de @ KennyTM ... Il devrait certainement être plus portable.
Cogwheel
3
attelle fait réellement la bonne chose. Ce n'est pas parce int32_tqu'il se trouve qu'il se trouve intsur votre compilateur / plateforme que cela peut ne pas être longsur un autre. Pareil pour size_t. En fait, il fait tout son possible et fait plus de travail pour détecter ce bogue de portabilité, car la vérification facile et naturelle serait simplement d'honorer le typedef comme le fait le compilateur.
R .. GitHub STOP HELPING ICE
4
-1, désolé ce n'est pas portable. Tout ce dont vous avez besoin est que les spécificateurs de format et les types concordent, et vous pouvez toujours effectuer un cast pour que cela soit vrai. long est au moins 32 bits, donc %luavec (unsigned long)kest toujours correct. size_test plus compliqué, c'est pourquoi a %zuété ajouté dans C99. Si vous ne pouvez pas l'utiliser, traitez-le comme k( longc'est le plus gros type de C89, il size_test très peu probable qu'il soit plus grand).
u0b34a0f6ae
139

Essayer

#include <inttypes.h>
...

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

Le zreprésente un entier de même longueur que size_t, et la PRIu32macro, définie dans l'en-tête C99inttypes.h , représente un entier 32 bits non signé.

KennyTM
la source
3
@robUK: Heh. Je vous suggère de déposer un bug pour l'attelle.
kennytm
8
C'est la bonne réponse. Bien que ma recommandation personnelle soit simplement de lancer, par exemple printf( "%lu", (unsigned long )i ). Sinon, on se retrouve plus tard avec une pile d'avertissements partout dans le code en raison d'un changement de type.
Dummy00001
1
C'est la bonne réponse. Je suis d'accord avec KennyTM sur le dépôt d'un bug pour l'attelle. Au fait, "% zu" est le format approprié pour size_t. Vous n'avez besoin d'aucune des macros PRI * pour imprimer size_t.
R .. GitHub STOP HELPING ICE
1
Si je me souviens bien,% zu est C99, et dans la question, il a écrit «C89».
alcor
8
@alcor oui il a mis C89 (apparemment le drapeau du compilateur gcc qu'il utilise) mais il l'utilise uint32_tdonc en fait c'est du code C99, et devrait être compilé comme tel.
Colin D Bennett
28

Tout ce dont vous avez besoin est que les spécificateurs de format et les types concordent, et vous pouvez toujours effectuer un cast pour que cela soit vrai. longest au moins 32 bits, donc %luavec (unsigned long)kest toujours correct:

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

size_test plus compliqué, c'est pourquoi a %zuété ajouté dans C99. Si vous ne pouvez pas l'utiliser, traitez-la commek ( longc'est le plus gros type de C89, il size_test très peu probable qu'il soit plus grand).

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

Si vous n'obtenez pas les spécificateurs de format corrects pour le type que vous passez, alors printffera l'équivalent de lire trop ou trop peu de mémoire hors du tableau. Tant que vous utilisez des casts explicites pour faire correspondre les types, c'est portable.

u0b34a0f6ae
la source
17

Si vous ne souhaitez pas utiliser les macros PRI *, une autre approche pour imprimer N'IMPORTE QUEL type entier consiste à convertir en intmax_tou uintmax_tet à utiliser "%jd"ou %ju, respectivement. Ceci est particulièrement utile pour les types POSIX (ou d'autres OS) qui n'ont pas de macros PRI * définies, par exemple off_t.

R .. GitHub STOP AIDING ICE
la source