How can one print a size_t variable portably using the printf family?
I have a variable of type size_t
, and I want to print it using printf()
. What format specifier do I use to print it portably?
In 32-bit machine, %u
seems right. I compiled with g++ -g -W -Wall -Werror -ansi -pedantic
, and there was no warning. But when I compile that code in 64-bit machine, it produces warning.
size_t x = <something>;
printf("size = %u\n", x);
warning: format '%u' expects type 'unsigned int',
but argument 2 has type 'long unsigned int'
The warning goes away, as expected, if I change that to %lu
.
The question is, how can I write the code, so that it compiles warning free on both 32- and 64- bit machines?
Edit: As a workaround, I guess one answer might be to "cast" the variable into an integer that is big enough, say unsigned long
, and print using %lu
. That would work in both cases. I am looking if there is any other idea.
Solution 1:
Use the z
modifier:
size_t x = ...;
ssize_t y = ...;
printf("%zu\n", x); // prints as unsigned decimal
printf("%zx\n", x); // prints as hex
printf("%zd\n", y); // prints as signed decimal
Solution 2:
Looks like it varies depending on what compiler you're using (blech):
-
gnu says
%zu
(or%zx
, or%zd
but that displays it as though it were signed, etc.) -
Microsoft says
%Iu
(or%Ix
, or%Id
but again that's signed, etc.) — but as of cl v19 (in Visual Studio 2015), Microsoft supports%zu
(see this reply to this comment)
...and of course, if you're using C++, you can use cout
instead as suggested by AraK.
Solution 3:
For C89, use %lu
and cast the value to unsigned long
:
size_t foo;
...
printf("foo = %lu\n", (unsigned long) foo);
For C99 and later, use %zu
:
size_t foo;
...
printf("foo = %zu\n", foo);
Solution 4:
Extending on Adam Rosenfield's answer for Windows.
I tested this code with on both VS2013 Update 4 and VS2015 preview:
// test.c
#include <stdio.h>
#include <BaseTsd.h> // see the note below
int main()
{
size_t x = 1;
SSIZE_T y = 2;
printf("%zu\n", x); // prints as unsigned decimal
printf("%zx\n", x); // prints as hex
printf("%zd\n", y); // prints as signed decimal
return 0;
}
VS2015 generated binary outputs:
1
1
2
while the one generated by VS2013 says:
zu
zx
zd
Note: ssize_t
is a POSIX extension and SSIZE_T
is similar thing in Windows Data Types, hence I added <BaseTsd.h>
reference.
Additionally, except for the follow C99/C11 headers, all C99 headers are available in VS2015 preview:
C11 - <stdalign.h>
C11 - <stdatomic.h>
C11 - <stdnoreturn.h>
C99 - <tgmath.h>
C11 - <threads.h>
Also, C11's <uchar.h>
is now included in latest preview.
For more details, see this old and the new list for standard conformance.
Solution 5:
For those talking about doing this in C++ which doesn't necessarily support the C99 extensions, then I heartily recommend boost::format. This makes the size_t type size question moot:
std::cout << boost::format("Sizeof(Var) is %d\n") % sizeof(Var);
Since you don't need size specifiers in boost::format, you can just worry about how you want to display the value.