The standard function fgets is specified this way in the upcoming C23 Standard:
7.23.7.2 The fgets function
Synopsis
#include <stdio.h> char *fgets(char * restrict s, int n, FILE * restrict stream);The
fgetsfunction reads at most one less than the number of characters specified bynfrom the stream pointed to bystreaminto the array pointed to bys. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.Returns
The
fgetsfunction returnssif successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned. If a read error occurs during the operation, the members of the array have unspecified values and a null pointer is returned.
This specification is unchanged since the original ANSI-C document, except for the restrict keywords added in C99.
The type specified for n is int, which is inconsistent with all other C library functions taking an array length or an object count where the type is size_t. This problem cannot be fixed without potentially breaking programs that use function pointers pointing to fgets or that pass negative values for n. fread and fwrite, along with many other standard functions used to have their numeric arguments and return values specified as int in the original Unix documents, but were changed before ANSI-C, which begs the question: Why was fgets left out of this update, was there any compelling reason to treat fgets() differently then?
Furthermore, some cases do not seem to have specified behavior:
- if
n <= 1, shouldfgets()returnswithout trying to read from the stream? - if
n == 1, shoulds[0]be set to a null character albeit no characters have been read into the array? - if
n <= 0, can we pass a null pointer fors?
Regarding the behavior for
n <= 1:There is no formal definition of successful in the context of this specification, and the only cases of failure that come to mind relate to reading from the stream and getting an error or reaching the end of file, both cases addressed in the specification.
Since
fgets()reads at most one less than the number of characters specified byn, it should not read any characters forn <= 1, hence not attempt any input from the stream. Therefore, thefgets()should returnsin this case.It seems unspecified if
smust be modified ands[0]set to a null character ifn == 1, albeit all C libraries for which I have access to the source code do behave this way.Because of this potential problem, It seems recommended to avoid calling
fgets()with a value below2for argumentn.Note that
snprintfhas a similar problem:The sentence and a null character is written at the end of the characters actually written into the array is somewhat ambiguous if no characters have actually been written to the array, either because the output is empty or because it has been completely discarded.
Despite this ambiguity, it seems impossible to argue that
snprintfgiven an empty format string may not produce an empty string insprovidednis non zero.It would be helpful to use a more precise specification of both
snprintfandfgetsregarding the case ofn == 1, ensuring thats[0]be set to a null character.