154

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?

hippietrail
  • 13,703
  • 15
  • 87
  • 133
Georg Schölly
  • 116,521
  • 48
  • 204
  • 258
  • 2
    @devin: I believe I've found that type while using `fopen`, `fseek`, etc. on Mac OS X. `off_t` is used for the offset. – Georg Schölly Mar 23 '10 at 17:40
  • [What's the correct way to use printf to print a size_t?](https://stackoverflow.com/q/940087/995714) – phuclv Jun 27 '18 at 07:11

9 Answers9

119

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.

Johannes Schaub - litb
  • 466,055
  • 116
  • 851
  • 1,175
  • Since PRId32 doesn't include the % format specifier, shouldn't that be `printf("value: %" PRId32, some_int32_t);` – Craig S Feb 26 '09 at 04:03
  • 3
    off_t is actually a signed long long on my system. – Georg Schölly Feb 27 '09 at 22:56
  • yeah for signed values you will have to convert to long or long long. this latter type does not exist in current C++ - but next version includes it. especially if you work with posix and it includes some types like off_t that have big sizes, you've to be careful. – Johannes Schaub - litb Feb 27 '09 at 23:20
  • then, i would use long long and proper formats if you know it supports long long. otherwise for embedded development where you know you only have to do with long as widest type, you can stick with long/unsigned long. – Johannes Schaub - litb Feb 27 '09 at 23:21
  • this question is about C. i forgot that. so i better mention in the answer that if you have long long available (as in c99) you should use that. – Johannes Schaub - litb Feb 27 '09 at 23:22
  • 2
    I think the man page discourages use of Z (uppercase) which was used by libc5. It doesn't seem to discourage z (lowercase). – Draemon May 26 '10 at 22:17
  • 13
    Using `%zd` with a `size_t` is **undefined behavior** due to the signedness mismatch (C99 7.19.6.1#9). It must be `%zu`. – Jens Mar 02 '13 at 08:31
  • 7
    Well, how to print off_t then? – JohnyTex Jul 25 '14 at 16:01
  • Very important Note: %zd and %zu don't work at visual studio 2010 - your application will CRASH! You should rather use %Iu (not L, it is big i). For more types see this: https://msdn.microsoft.com/en-us/library/tcxf1dw6(v=vs.100).aspx – David Constantine Feb 16 '16 at 08:52
  • 3
    @Jens I don’t see how `%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. – Chortos-2 Oct 29 '16 at 18:54
  • @JohannesSchaub-litb You say "You can use z" but below it says "%zu". What does that mean, for a noob like me? I googled and "u" means unsigned. Why didn't you write "You can use zu" intead? – Santropedro Jun 17 '19 at 00:08
  • 1
    @Santropedro when I mentioned z and t, (the second one actually should be `%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`. – Johannes Schaub - litb Jun 17 '19 at 08:30
  • @JohannesSchaub-litb How is `%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. – Pryftan Dec 03 '19 at 15:29
112

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.

Steve Jessop
  • 257,525
  • 32
  • 431
  • 672
  • 3
    This is by far the better answer, I would have forgotten about using %zu for unsigned size_t. And casting to intmax_t is a great solution to whatever off_t is on any platform. – Peter Cordes Dec 28 '14 at 01:13
  • 3
    POSIX doesn't guarantee that `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`. – nwellnhof Sep 30 '17 at 15:11
  • off_t can be upto size long long and can be variable depending on defines... Visual Studio warns with this also "warning C4477: '_snprintf_s' : format string '%jd' requires an argument of type '__int64', but variadic argument 1 has type 'off_t'"... A truely portable way is printf("%lld\n", (long long)x); – ericcurtin Jun 13 '18 at 16:59
5

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.

NoBrassRing
  • 355
  • 4
  • 13
3

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.

David Thornley
  • 54,186
  • 8
  • 87
  • 153
3

You'll want to use the formatting macros from inttypes.h.

See this question: Cross platform format string for variables of type size_t?

Community
  • 1
  • 1
Michael Burr
  • 311,791
  • 49
  • 497
  • 724
  • Assuming that off_t is a signed, pointer-sized int (I don't know what the precise definition is) like ptrdiff_t then you'd use PRIdPTR or PRIiPTR. – Michael Burr Apr 27 '09 at 20:31
  • 11
    The `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). – Dietrich Epp May 24 '10 at 23:22
  • 1
    @DietrichEpp: Actually, it's worse than that; many 32-bit systems have both off_t and off64_t, and depending on the feature macros off_t may actually mean off64_t. – SamB Jul 31 '14 at 02:05
1

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).

dwc
  • 21,894
  • 6
  • 41
  • 54
-3

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.

Community
  • 1
  • 1
Elinx
  • 1,096
  • 11
  • 18
  • 1
    For C99 and C11, the standard explicitly states that `%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. – autistic Sep 20 '17 at 04:19
-4

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));
Alex B
  • 75,980
  • 39
  • 193
  • 271
James Curran
  • 95,648
  • 35
  • 171
  • 253
-9

use "%zo" for off_t. (octal) or "%zu" for decimal.

Shankar
  • 1
  • 1