在单元测试中,函数包含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
and neither feof()
nor ferror()
are 1
.
下面的 C 规范似乎对这种罕见的情况保持沉默。
问题:
- 正在返回
NULL
无需设置feof()
nor ferror()
合规行为?
- 不同的结果是否是合规行为?
- 如果有的话有什么区别吗
n
是1还是小于1?
平台:gcc 版本 4.5.3 目标:i686-pc-cygwin
以下是 C11 标准的摘要,其中有一些重点:
7.21.7.2fgets
功能
The fgets函数读取的字符数最多比指定的字符数少一个n [...]
The fgets函数返回s如果成功的话。如果遇到文件结尾and没有字符被读入数组,数组的内容保持不变并返回空指针。如果操作过程中发生读取错误,则数组内容不确定并返回空指针。
相关帖子
如何对 fgets 使用 feof 和ferror(C 语言中的 minishell) https://stackoverflow.com/questions/21724004/minishell-in-c-how-to-use-feof-and-ferror-for-fgets
在 C 中创建 shell 时遇到问题(Seg-Fault 和ferror) https://stackoverflow.com/questions/12716276/trouble-creating-a-shell-in-c-seg-fault-and-ferror
fputs()、fgets()、ferror() 问题和 C++ 等效项 https://stackoverflow.com/questions/9059486/fputs-fgets-ferror-questions-and-c-equivalents
fgets()的返回值 https://stackoverflow.com/questions/21679063/return-value-of-fgets
[编辑]对答案的评论
@Shafik Yaghmour 很好地提出了总体问题:因为 C 规范没有提到当它不读取时要做什么any数据也不写any数据到s
when (n <= 0
),这是未定义的行为。因此任何合理的回应都应该是可以接受的,例如退货NULL
,不设置标志,保留缓冲区。
至于什么时候应该发生什么n==1
,@Oliver Matthews 的回答和 @Matt McNabb 的评论表明,考虑到缓冲区,C 规范缺乏清晰度n == 1
。 C 规范seems有利于缓冲n == 1
应该返回缓冲区指针s[0] == '\0'
,但还不够明确。