How to use "zd" specifier with `printf()`?
printf
with a "%zd"
format expects an argument of the signed type that corresponds to the unsigned type size_t
.
Standard C doesn't provide a name for this type or a good way to determine what it is. If size_t
is a typedef for unsigned long
, for example, then "%zd"
expects an argument of type long
, but that's not a portable assumption.
The standard requires that corresponding signed and unsigned types use the same representation for the non-negative values that are representable in both types. A footnote says that this is meant to imply that they're interchangeable as function arguments. So this:
size_t s = 42;
printf("s = %zd\n", s);
should work, and should print "42". It will interpret the value 42
, of the unsigned type size_t
, as if it were of the corresponding signed type. But there's really no good reason to do that, since "%zu"
is also correct and well defined, without resorting to additional language rules. And "%zu"
works for all values of type size_t
, including those outside the range of the corresponding signed type.
Finally, POSIX defines a type ssize_t
in the headers <unistd.h>
and <sys/types.h>
. Though POSIX doesn't explicitly say so, it's likely that ssize_t
will be the signed type corresponding to size_t
.
So if you're writing POSIX-specific code, "%zd"
is (probably) the correct format for printing values of type ssize_t
.
UPDATE: POSIX explicitly says that ssize_t
isn't necessarily the signed version of size_t
, so it's unwise to write code that assumes that it is:
ssize_t
This is intended to be a signed analog of
size_t
. The wording is such that an implementation may either choose to use a longer type or simply to use the signed version of the type that underliessize_t
. All functions that returnssize_t
(read()
andwrite())
describe as "implementation-defined" the result of an input exceeding {SSIZE_MAX
}. It is recognized that some implementations might haveint
s that are smaller thansize_t
. A conforming application would be constrained not to perform I/O in pieces larger than {SSIZE_MAX
}, but a conforming application using extensions would be able to use the full range if the implementation provided an extended range, while still having a single type-compatible interface. The symbolssize_t
andssize_t
are also required in<unistd.h>
to minimize the changes needed for calls toread()
andwrite()
. Implementors are reminded that it must be possible to include both<sys/types.h>
and<unistd.h>
in the same program (in either order) without error.