The venerable snprintf() function…
int snprintf( char *restrict buffer, size_t bufsz, const char *restrict format, ... );
it:
- Returns the number of characters it prints, or rather, the number it would have printed had it not been for the buffer size limit.
- Takes the size of the buffer in characters/bytes.
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?
>Solution :
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 anintwith substantially the same significance. This was defined (for the originalprintf,fprintf, andsprintf) well beforesize_twas invented. -
type
size_tis in some sense the correct type for conveying sizes and lengths, so it was used for the second arguments tosnprintfandvsnprintfwhen those were introduced (along withsize_titself) in C99.
If
snprintf()is supposed to be able to print more thanINT_MAXcharacters into the buffer, surely it must return anssize_tor asize_twith(size_t) - 1indicating 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_MAXcharacters, why is bufsz asize_trather than, say, anunsignedor 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).