Looking for clarification on using "zd" with printf().
Certainly the following is correct with C99 and later.
void print_size(size_t sz) {
printf("%zu\n", sz);
}
The C spec seems to allow printf("%zd\n", sz) depending on how it is read:
7.21.6.1 The fprintf function
zSpecifies that a followingd,i,o,u,x, orXconversion specifier applies to asize_tor the corresponding signed integer type argument; or that a followingnconversion specifier applies to a pointer to a signed integer type corresponding tosize_targument. C11dr §7.21.6.1 7
Should this be read as
z Specifies that a following d ... conversion specifier applies to a size_t or the corresponding signed integer type argument ... "(both types) and "z Specifies that a following u ... conversion specifier applies to a size_t or the corresponding signed integer type argument ..." (both types)OR
z Specifies that a following d ... conversion specifier applies to a corresponding signed integer type argument ..." (signed type only) and "z Specifies that a following u ... conversion specifier applies to a size_t" (unsigned type only).I've been using the #2 definition, but now not so sure.
Which is correct, 1, 2, or something else?
If #2 is correct, what is an example of a type that can use
"%zd"?
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.
The %a formatting specifier is new in C99. It prints the floating-point number in hexadecimal form. This is not something you would use to present numbers to users, but it's very handy for under-the-hood/technical use cases. As an example, this code: printf("pi=%a\n", 3.14);
Format specifiers in C are used to take inputs and print the output of a type. The symbol we use in every format specifier is %.
rL295112: Use "%zd" format specifier for printing number of testcases executed. This helps to avoid signed integer overflow after running a fast fuzz target for several hours, e.g.: <...>
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_tThis 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 haveints 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_tandssize_tare 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With