I'm trying to print types like off_t
and size_t
. What is the correct placeholder for printf()
that is portable?
Or is there a completely different way to print those variables?
I'm trying to print types like off_t
and size_t
. What is the correct placeholder for printf()
that is portable?
Or is there a completely different way to print those variables?
You can use z
for size_t and t
for ptrdiff_t like in
printf("%zu %td", size, ptrdiff);
But my manpage says some older library used a different character than z
and discourages use of it. Nevertheless, it's standardized (by the C99 standard). For those intmax_t
and int8_t
of stdint.h
and so on, there are macros you can use, like another answer said:
printf("value: %" PRId32, some_int32_t);
printf("value: %" PRIu16, some_uint16_t);
They are listed in the manpage of inttypes.h
.
Personally, I would just cast the values to unsigned long
or long
like another answer recommends. If you use C99, then you can (and should, of course) cast to unsigned long long
or long long
and use the %llu
or %lld
formats respectively.
printf("value: %" PRId32, some_int32_t);
–
Recliner %zd
with a size_t
is undefined behavior due to the signedness mismatch (C99 7.19.6.1#9). It must be %zu
. –
Osher %zd
with a size_t
gets undefined behaviour from that paragraph or from any other. In fact, the definition of %z
in #7 explicitly allows %d
with size_t
and the corresponding signed type, and §6.2.5#9 explicitly allows using values of unsigned types where the corresponding signed type is expected, as long as the value is a valid nonnegative value of the signed type. –
Woodman %td
), I referred to modifiers. Like you say, u
means unsigned, and d
means signed. size_t exist in signed and unsigned versions (size_t and ssize_t). The important information is z
, as it means "signed or unsigned size_t". Had you written %lu
it meant long signed
, for example. Google for man 3 printf
. –
Molecule %lu
long signed
? When you say: Had you written ... it meant ...' I would also argue that size_t
doesn't have more than one version; rather it's a typedef though I guess if you call signed versus unsigned 'versions' you could argue that size_t and ssize_t are versions. –
Etna To print off_t
:
printf("%jd\n", (intmax_t)x);
To print size_t
:
printf("%zu\n", x);
To print ssize_t
:
printf("%zd\n", x);
See 7.19.6.1/7 in the C99 standard, or the more convenient POSIX documentation of formatting codes:
http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
If your implementation doesn't support those formatting codes (for example because you're on C89), then you have a bit of a problem since AFAIK there aren't integer types in C89 that have formatting codes and are guaranteed to be as big as these types. So you need to do something implementation-specific.
For example if your compiler has long long
and your standard library supports %lld
, you can confidently expect that will serve in place of intmax_t
. But if it doesn't, you'll have to fall back to long
, which would fail on some other implementations because it's too small.
ssize_t
has the same size as size_t
, so truly portable code should convert it to intmax_t
and print with %jd
just like off_t
. –
Burnt You can use z
for size_t and t
for ptrdiff_t like in
printf("%zu %td", size, ptrdiff);
But my manpage says some older library used a different character than z
and discourages use of it. Nevertheless, it's standardized (by the C99 standard). For those intmax_t
and int8_t
of stdint.h
and so on, there are macros you can use, like another answer said:
printf("value: %" PRId32, some_int32_t);
printf("value: %" PRIu16, some_uint16_t);
They are listed in the manpage of inttypes.h
.
Personally, I would just cast the values to unsigned long
or long
like another answer recommends. If you use C99, then you can (and should, of course) cast to unsigned long long
or long long
and use the %llu
or %lld
formats respectively.
printf("value: %" PRId32, some_int32_t);
–
Recliner %zd
with a size_t
is undefined behavior due to the signedness mismatch (C99 7.19.6.1#9). It must be %zu
. –
Osher %zd
with a size_t
gets undefined behaviour from that paragraph or from any other. In fact, the definition of %z
in #7 explicitly allows %d
with size_t
and the corresponding signed type, and §6.2.5#9 explicitly allows using values of unsigned types where the corresponding signed type is expected, as long as the value is a valid nonnegative value of the signed type. –
Woodman %td
), I referred to modifiers. Like you say, u
means unsigned, and d
means signed. size_t exist in signed and unsigned versions (size_t and ssize_t). The important information is z
, as it means "signed or unsigned size_t". Had you written %lu
it meant long signed
, for example. Google for man 3 printf
. –
Molecule %lu
long signed
? When you say: Had you written ... it meant ...' I would also argue that size_t
doesn't have more than one version; rather it's a typedef though I guess if you call signed versus unsigned 'versions' you could argue that size_t and ssize_t are versions. –
Etna For Microsoft, the answer is different. VS2013 is largely C99 compliant but "[t]he hh, j, z, and t length prefixes are not supported." For size_t "that is, unsigned __int32 on 32-bit platforms, unsigned __int64 on 64-bit platforms" use prefix I (capital eye) with type specifier o, u, x, or X. See VS2013 Size specification
As for off_t, it is defined as long in VC\include\sys\types.h.
off_t
is always long
that would make it 32-bit (even 64-bit Windows uses 32-bit for long
). –
Izmir You'll want to use the formatting macros from inttypes.h.
See this question: Cross platform format string for variables of type size_t?
off_t
type is larger than a pointer on any 32-bit system that supports large files (which is most 32-bit systems these days). –
Mental Which version of C are you using?
In C90, the standard practice is to cast to signed or unsigned long, as appropriate, and print accordingly. I've seen %z for size_t, but Harbison and Steele don't mention it under printf(), and in any case that wouldn't help you with ptrdiff_t or whatever.
In C99, the various _t types come with their own printf macros, so something like "Size is " FOO " bytes."
I don't know details, but that's part of a fairly large numeric format include file.
Looking at man 3 printf
on Linux, OS X, and OpenBSD all show support for %z
for size_t
and %t
for ptrdiff_t
(for C99), but none of those mention off_t
. Suggestions in the wild usually offer up the %u
conversion for off_t
, which is "correct enough" as far as I can tell (both unsigned int
and off_t
vary identically between 64-bit and 32-bit systems).
unsigned int
and 64-bit off_t
. So the cast would cause data to be lost. –
Mental off_t
has to be a signed type, so I wouldn't recommend this. –
Eras If you use C11 or C18, you can use _Generic
.
#include <stdio.h>
#include <sys/types.h>
#define TYPE_FORMAT(variable) _Generic \
( \
(variable) \
, unsigned char : "%hhu" \
, unsigned short : "%hu" \
, unsigned int : "%u" \
, unsigned long : "%lu" \
, unsigned long long : "%llu" \
, signed char : "%hhi" \
, signed short : "%hi" \
, signed int : "%i" \
, signed long : "%li" \
, signed long long : "%lli" \
)
int main(void)
{
off_t a=3321;
printf(TYPE_FORMAT(a), a);
}
However, there is one major drawback: You can not combine strings this way. Means this:
printf("Foo: " TYPE_FORMAT(a), a);
will not work, which makes it useless for many situation. Yes you could combine the string during runtime but that is annoying.
I saw this post at least twice, because the accepted answer is hard to remeber for me(I rarely use z
or j
flags and they are seems not platform independant).
The standard never says clearly the exact data length of size_t
, so I suggest you should first check the length size_t
on your platform then select one of them:
if sizeof(size_t) == 4 use PRIu32
if sizeof(size_t) == 8 use PRIu64
And I suggest using stdint
types instead of raw data types for consistancy.
%zu
can be used to print size_t
values. One should definitely not resort to using a uint32_t
/uint64_t
format specifier to print a size_t
, as there's no guarantee that those types are compatible. –
Mouldy As I recall, the only portable way to do it, is to cast the result to "unsigned long int" and use %lu
.
printf("sizeof(int) = %lu", (unsigned long) sizeof(int));
long long
does not exist in the C++ standard, and is thus inherently non-portable. –
Oxheart use "%zo" for off_t. (octal) or "%zu" for decimal.
© 2022 - 2024 — McMap. All rights reserved.
fopen
,fseek
, etc. on Mac OS X.off_t
is used for the offset. – Anson