Comment dois-je imprimer des types comme off_t et size_t?

148

J'essaye d'imprimer des types comme off_tet size_t. Quel est l'espace réservé correct pour printf() qui est portable ?

Ou y a-t-il une manière complètement différente d'imprimer ces variables?

Georg Schölly
la source
2
@devin: Je crois que je l' ai trouvé ce type tout en utilisant fopen, fseeketc. sous Mac OS X. off_test utilisé pour le décalage.
Georg Schölly

Réponses:

112

Vous pouvez utiliser zpour size_t et tpour ptrdiff_t comme dans

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

Mais ma page de manuel indique que certaines bibliothèques plus anciennes utilisaient un caractère différent de celui-ci zet en déconseillent l'utilisation. Néanmoins, il est standardisé (par la norme C99). Pour ceux intmax_tet int8_tde stdint.het ainsi de suite, il y a des macros que vous pouvez utiliser, comme une autre réponse dit:

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

Ils sont répertoriés dans la page de manuel de inttypes.h.

Personnellement, je ferais simplement passer les valeurs unsigned longou longcomme le recommande une autre réponse. Si vous utilisez C99, vous pouvez (et devriez, bien sûr) lancer vers unsigned long longou long longet utiliser le%llu%lld respectivement les formats ou .

Johannes Schaub - litb
la source
2
off_t est en fait un long long signé sur mon système.
Georg Schölly
2
Je pense que la page de manuel décourage l'utilisation de Z (majuscule) qui a été utilisé par libc5. Cela ne semble pas décourager z (minuscule).
Draemon
12
L'utilisation %zdavec a size_test un comportement indéfini en raison de l'incohérence de signature (C99 7.19.6.1 # 9). Ça doit être %zu.
Jens
7
Eh bien, comment imprimer off_t alors?
JohnyTex
3
@Jens Je ne vois pas comment %zdun size_tobtient un comportement non défini de ce paragraphe ou de tout autre. En fait, la définition de %zin # 7 autorise explicitement %davec size_tet le type signé correspondant, et §6.2.5 # 9 permet explicitement d'utiliser des valeurs de types non signés où le type signé correspondant est attendu, tant que la valeur est une valeur non négative valide du type signé.
Chortos-2
108

Pour imprimer off_t:

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

Pour imprimer size_t:

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

Pour imprimer ssize_t:

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

Voir 7.19.6.1/7 dans la norme C99, ou la documentation POSIX plus pratique des codes de formatage:

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

Si votre implémentation ne prend pas en charge ces codes de formatage (par exemple parce que vous êtes sur C89), alors vous avez un petit problème car AFAIK il n'y a pas de types entiers dans C89 qui ont des codes de formatage et sont garantis aussi gros comme ces types. Vous devez donc faire quelque chose de spécifique à l'implémentation.

Par exemple, si votre compilateur a long longet que votre bibliothèque standard le prend en charge %lld, vous pouvez vous attendre à ce que cela serve à la place de intmax_t. Mais si ce n'est pas le cas, vous devrez vous rabattre sur long, ce qui échouerait sur certaines autres implémentations car il est trop petit.

Steve Jessop
la source
3
C'est de loin la meilleure réponse, j'aurais oublié d'utiliser% zu pour un size_t non signé. Et la conversion en intmax_t est une excellente solution pour tout ce que off_t est sur n'importe quelle plate-forme.
Peter Cordes
2
POSIX ne garantit pas qu'il ssize_ta la même taille que size_t, donc un code vraiment portable devrait le convertir intmax_tet l'imprimer avec %jdcomme off_t.
nwellnhof
off_t peut être jusqu'à size long long et peut être variable en fonction de la définition ... Visual Studio avertit avec ceci également "avertissement C4477: '_snprintf_s': la chaîne de format '% jd' nécessite un argument de type '__int64', mais l'argument variadique 1 a le type 'off_t' "... Un moyen vraiment portable est printf ("% lld \ n ", (long long) x);
ericcurtin
5

Pour Microsoft, la réponse est différente. VS2013 est en grande partie conforme à C99 mais "[l] es préfixes de longueur hh, j, z et t ne sont pas pris en charge." Pour size_t "c'est-à-dire __int32 non signé sur les plates-formes 32 bits, __int64 non signé sur les plates-formes 64 bits", utilisez le préfixe I (œil majuscule) avec le spécificateur de type o, u, x ou X. Voir la spécification de taille VS2013

Quant à off_t, il est défini comme long dans VC \ include \ sys \ types.h.

NoBrassBague
la source
Notez que si off_tc'est toujours longcela le rendrait 32 bits (même Windows 64 bits utilise 32 bits pour long).
sourcejedi
3

Quelle version de C utilisez-vous?

Dans C90, la pratique courante consiste à convertir en caractères longs signés ou non signés, selon le cas, et à imprimer en conséquence. J'ai vu% z pour size_t, mais Harbison et Steele ne le mentionnent pas sous printf (), et en tout cas cela ne vous aiderait pas avec ptrdiff_t ou autre.

Dans C99, les différents types _t sont livrés avec leurs propres macros printf, donc quelque chose comme "Size is " FOO " bytes." je ne connais pas les détails, mais cela fait partie d'un fichier d'inclusion de format numérique assez grand.

David Thornley
la source
3

Vous voudrez utiliser les macros de mise en forme de inttypes.h.

Voir cette question: Chaîne de format multiplateforme pour les variables de type size_t?

Michael Burr
la source
En supposant que off_t est un entier signé de la taille d'un pointeur (je ne sais pas quelle est la définition précise) comme ptrdiff_t, vous utiliseriez PRIdPTR ou PRIiPTR.
Michael Burr
11
Le off_ttype est plus grand qu'un pointeur sur n'importe quel système 32 bits qui prend en charge de gros fichiers (ce qui est la plupart des systèmes 32 bits de nos jours).
Dietrich Epp
1
@DietrichEpp: En fait, c'est pire que ça; de nombreux systèmes 32 bits ont à la fois off_t et off64_t, et selon la fonctionnalité, les macros off_t peuvent en fait signifier off64_t.
SamB
1

En regardant man 3 printfsur Linux, OS X et OpenBSD, tous montrent le support %zpour size_tet %tpour ptrdiff_t(pour C99), mais aucun de ceux-ci ne le mentionne off_t. Les suggestions dans la nature offrent généralement la %uconversion pour off_t, ce qui est "assez correct" pour autant que je sache (les deux unsigned intet off_tvarient de la même manière entre les systèmes 64 bits et 32 ​​bits).

dwc
la source
1
Mon système (OS X) a 32 bits unsigned intet 64 bits off_t. Ainsi, le casting entraînerait la perte de données.
Dietrich Epp
-3

J'ai vu ce post au moins deux fois, car la réponse acceptée est difficile à retenir pour moi (j'utilise rarement zou des jdrapeaux et ils ne semblent pas indépendants de la plate-forme ).

La norme ne dit jamais clairement la longueur exacte des données de size_t, donc je vous suggère de vérifier d'abord la longueur size_tsur votre plate-forme, puis de sélectionner l'une d'entre elles:

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

Et je suggère d'utiliser des stdinttypes au lieu de types de données brutes pour la cohérence.

elinx
la source
1
Pour C99 et C11, la norme indique explicitement qui %zupeut être utilisée pour imprimer des size_tvaleurs. Il ne faut certainement pas recourir à un spécificateur uint32_t/ uint64_tformat pour imprimer un size_t, car il n'y a aucune garantie que ces types sont compatibles.
autiste
-4

Si je me souviens bien, la seule façon portable de le faire est de convertir le résultat en "unsigned long int" et de l'utiliser %lu.

printf("sizeof(int) = %lu", (unsigned long) sizeof(int));
James Curran
la source
1
Doit être "% lu", car le modificateur de longueur doit venir avant la conversion.
dwc
1
off_t par exemple est un long long signé.
Georg Schölly
@ GeorgSchölly - Ensuite, vous êtes confronté à une énigme, car il long longn'existe pas dans la norme C ++, et est donc intrinsèquement non portable.
James Curran
-9

utilisez "% zo" pour off_t. (octal) ou "% zu" pour décimal.

Shankar
la source
Pourquoi voudriez-vous que le fichier soit décalé en octal?
poolie