В модульном тестировании функция, содержащая fgets()
, встретила неожиданный результат при размере буфера n < 2
. Очевидно, что такой размер буфера является глупым, но тест исследует угловые случаи.
Упрощенный код:
#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\n", s, n, stream);
char *retval = fgets(s, n, stream);
printf("> errno:%d feof:%d ferror:%d retval:%p s[0]:%d\n\n",
errno, feof(stream), ferror(stream), retval, s[0]);
}
int main(void) {
char s[100];
test_fgets(s, sizeof s); // Entered "123\n" and works as expected
test_fgets(s, 1); // fgets() --> NULL, feof() --> 0, ferror() --> 0
test_fgets(s, 0); // Same as above
return 0;
}
Удивительно, что fgets()
возвращает NULL
, и ни feof()
, ни ferror()
не являются 1
.
В этом редком случае, как показано ниже, C spec кажется тихим.
Вопросы:
- Возвращает
NULL
без установкиfeof()
иferror()
совместимого поведения? - Может ли другой результат быть совместимым поведением?
- Имеет ли значение, если
n
равно 1 или меньше 1?
Платформа: версия gcc 4.5.3 Цель: i686-pc-cygwin
Вот аннотация из стандарта C11, некоторые мои замечания:
7.21.7.2 Функция
fgets
Функция fgets читает не более, чем число символов, указанное n [...]
Функция fgets возвращает s в случае успеха. Если конец файла встречается и в массив не считываются символы, содержимое массива остается неизменным и возвращается нулевой указатель. Если во время операции возникает ошибка чтения, содержимое массива является неопределенным и возвращается нулевой указатель.
Связанные публикации
Как использовать feof и ferror для fgets (minishell in C)
Проблема с созданием оболочки в C (Seg-Fault и ferror)
функции fputs(), fgets(), ferror() и эквиваленты С++
Возвращаемое значение fgets()
[Изменить] Комментарии к ответам
@Shafik Yaghmour хорошо представил общую проблему: поскольку спецификация C не упоминает, что делать, когда она не читает никаких данных и не записывает никаких данных в s
, когда (n <= 0
), это Undefined Поведение, Поэтому любой разумный ответ должен быть приемлемым, например return NULL
, не устанавливать флаги, оставлять буфер самостоятельно.
Что касается того, что должно произойти, когда n==1
, ответ @Oliver Matthews и комментарий @Matt McNabb указывают на отсутствие ясности C spec с учетом буфера n == 1
. Спектр C, похоже, поддерживает буфер n == 1
, который должен возвращать указатель буфера с помощью s[0] == '\0'
, но не достаточно явным.