The venerable snprintf()
function...
int snprintf( char *restrict buffer, size_t bufsz, const char *restrict format, ... );
How does it make sense for the buffer size to be size_t
, but for the return type to be only an int
?
If snprintf()
is supposed to be able to print more than INT_MAX
characters into the buffer, surely it must return an ssize_t
or a size_t
with (size_t) - 1
indicating an error, right?
And if it is not supposed to be able to print more than INT_MAX
characters, why is bufsz
a size_t
rather than, say, an unsigned
or an int
? Or - is it at least officially constrained to hold values no larger than INT_MAX
?
How does it make sense for the buffer size to be
size_t
, but for the return type to be only an int?
The official C99 rationale document does not discuss these particular considerations, but presumably it's for consistency and (separate) ideological reasons:
all of the printf
-family functions return an int
with substantially the same significance. This was defined (for the original printf
, fprintf
, and sprintf
) well before size_t
was invented.
type size_t
is in some sense the correct type for conveying sizes and lengths, so it was used for the second arguments to snprintf
and vsnprintf
when those were introduced (along with size_t
itself) in C99.
If
snprintf()
is supposed to be able to print more thanINT_MAX
characters into the buffer, surely it must return anssize_t
or asize_t
with(size_t) - 1
indicating an error, right?
That would be a more internally-consistent design choice, but nope. Consistency across the function family seems to have been chosen instead. Note that none of the functions in this family have documented limits on the number of characters they can output, and their general specification implies that there is no inherent limit. Thus, they all suffer from the same issue with very long outputs.
And if it is not supposed to be able to print more than
INT_MAX
characters, why is bufsz asize_t
rather than, say, anunsigned
or anint
? Or - is it at least officially constrained to hold values no larger thanINT_MAX
?
There is no documented constraint on the value of the second argument, other than the implicit one that it must be representable as a size_t
. Not even in the latest version of the standard. But note that there is also nothing that says that type int
cannot represent all the values that are representable by size_t
(though indeed it can't in most implementations).
So yes, implementations will have trouble behaving according to the specifications when very large data are output via these functions, where "very large" is implementation-dependent. As a practical matter, then, one should not rely on using them to emit very large outputs in a single call (unless one intends to ignore the return value).