In any reasonably modern C implementation, "%zu"
is the correct way to print a value of type size_t
:
printf("sizeof (int) = %zu\n", sizeof (int));
The "%zu"
format specifier was added in the 1999 ISO C standard (and adopted by the 2011 ISO C++ standard). If you don't need to be concerned about implementations older than that, you can stop reading now.
If your code needs to be portable to pre-C99 implementations, you can cast the value to unsigned long
and use "%lu"
:
printf("sizeof (int) = %lu\n", (unsigned long)sizeof (int));
That's not portable to C99 or later, because C99 introduced long long
and unsigned long long
, and therefore the possibility that size_t
is wider than unsigned long
.
Resist the temptation to use "%lu"
or "%llu"
without the cast. The type used to implement size_t
is implementation-defined, and if the types don't match, the behavior is undefined. Something like printf("%lu\n", sizeof (int));
might "work", but it's not at all portable.
In principle, the following should cover all possible cases:
#if __STDC_VERSION__ < 199901L
printf("sizeof (int) = %lu\n", (unsigned long)sizeof (int));
#else
printf("sizeof (int) = %zu\n", sizeof (int));
#endif
In practice, it might not always work correctly. __STD_VERSION__ >= 199901L
should guarantee that "%zu"
is supported, but not all implementations are necessarily correct, especially since __STD_VERSION__
is set by the compiler and "%zu"
is implemented by the runtime library. For example, an implementation with partial C99 support might implement long long
and make size_t
a typedef for unsigned long long
, but not support "%zu"
. (Such an implementation likely wouldn't define __STDC_VERSION__
.)
It's been pointed out that Microsoft's implementation can have 32-bit unsigned long
and 64-bit size_t
. Microsoft does support "%zu"
, but that support was added relatively late. On the other hand, casting to unsigned long
will be a problem only if the particular size_t
value happens to exceed ULONG_MAX
, which is unlikely to happen in practice.
If you're able to assume reasonably modern implementations, just use "%zu"
. If you need to allow for older implementations, here's an absurdly portable program that adapts to various configurations:
#include <stdio.h>
#include <limits.h>
int main(void) {
const size_t size = -1; /* largest value of type size_t */
#if __STDC_VERSION__ < 199901L
if (size > ULONG_MAX) {
printf("size is too big to print\n");
}
else {
printf("old: size = %lu\n", (unsigned long)size);
}
#else
printf("new: size = %zu\n", size);
#endif
return 0;
}
One implementation that prints "size is too big to print" (x86_64-w64-mingw32-gcc.exe -std=c90
on Windows/Cygwin) actually supports unsigned long long
as an extension on top of C90, so you might be able to take advantage of that -- but I can imagine a pre-C99 implementation that supports unsigned long long
but doesn't support "%llu"
. And that implementation supports "%zu"
anyway.
In my experience, I've only wanted to print size_t
values in quick throwaway code when I'm exploring an implementation rather than in production code. In that kind of context, it's probably sufficient just to do whatever works.
(The question is about C, but I'll mention that in C++ std::cout << sizeof (int)
will work correctly in any version of the language.)
unsigned long
is the best option if your libc implementation doesn't support thez
modifier; the C99 standard recommendssize_t
not to have an integer conversion rank greater thanlong
, so you're reasonably safe – Christoph