In unit testing a function containing fgets()
, came across an unexpected result when the buffer size n < 2
. Obviously such a buffer size is foolish, but the test is exploring corner cases.
Simplified code:
#include <error.h>
#include <stdio.h>
void test_fgets(char * restrict s, int n) {
FILE *stream = stdin;
s[0] = 42;
printf("< s:%p n:%d stream:%p
", s, n, stream);
char *retval = fgets(s, n, stream);
printf("> errno:%d feof:%d ferror:%d retval:%p s[0]:%d
",
errno, feof(stream), ferror(stream), retval, s[0]);
}
int main(void) {
char s[100];
test_fgets(s, sizeof s); // Entered "123
" and works as expected
test_fgets(s, 1); // fgets() --> NULL, feof() --> 0, ferror() --> 0
test_fgets(s, 0); // Same as above
return 0;
}
What is surprising is that fgets()
returns NULL
and neither feof()
nor ferror()
are 1
.
The C spec, below, seems silent on this rare case.
Questions:
- Is returning
NULL
without setting feof()
nor ferror()
compliant behavior?
- Could a different result be compliant behavior?
- Does it make a difference if
n
is 1 or less than 1?
Platform: gcc version 4.5.3 Target: i686-pc-cygwin
Here is an abstract from the C11 Standard, some emphasis mine:
7.21.7.2 The fgets
function
The fgets function reads at most one less than the number of characters specified by n [...]
The fgets function returns s if 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 array contents are indeterminate and a null pointer is returned.
Related postings
How to use feof and ferror for fgets (minishell in C)
Trouble creating a shell in C (Seg-Fault and ferror)
fputs(), fgets(), ferror() questions and C++ equivalents
Return value of fgets()
[Edit] Comments on answers
@Shafik Yaghmour well presented the overall issue: since the C spec does not mention what to do when it does not read any data nor write any data to s
when (n <= 0
), it is Undefined Behavior. So any reasonable response should be acceptable such as return NULL
, set no flags, leave buffer alone.
As to what should happen when n==1
, @Oliver Matthews answer and @Matt McNabb comment indicate a C spec's lack of clarity considering a buffer of n == 1
. The C spec seems to favor a buffer of n == 1
should return the buffer pointer with s[0] == ''
, but is not explicit enough.
Question&Answers:
os