fgets()返回的NULL是否与短缓冲区兼容? [英] Is fgets() returning NULL with a short buffer compliant?

查看:448
本文介绍了fgets()返回的NULL是否与短缓冲区兼容?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在对包含fgets()的函数进行单元测试时,当缓冲区大小n < 2时遇到意外结果.显然,这样的缓冲区大小是愚蠢的,但是测试正在探索极端情况.

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.

简化代码:

#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.

What is surprising is that fgets() returns NULL and neither feof() nor ferror() are 1.

下面的C规范似乎对这种罕见情况保持沉默.

The C spec, below, seems silent on this rare case.

问题:

  • 是否在未设置feof()ferror()兼容行为的情况下返回NULL?
  • 是否会有其他结果是合规行为?
  • n为1或小于1是否有所不同?
  • 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?

平台:gcc版本4.5.3目标:i686-pc-cygwin

Platform: gcc version 4.5.3 Target: i686-pc-cygwin

这里是C11标准的摘要,其中有些是我的重点:

Here is an abstract from the C11 Standard, some emphasis mine:

7.21.7.2 fgets功能

7.21.7.2 The fgets function

fgets 函数读取的字符数最多少于 n [...]

The fgets function reads at most one less than the number of characters specified by n [...]

如果成功, fgets 函数将返回 s .如果遇到文件结尾 并且没有字符读入数组,则数组的内容保持不变,并返回空指针.如果在操作过程中发生读取错误,则数组内容不确定,并返回空指针.

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.

相关帖子
如何将feof和ferror用于fget(minishell)在C中)
在C语言中创建shell时遇到问题(Seg-Fault和ferror )
> fputs(),fgets(),ferror()问题和C ++等效项
fgets()的返回值

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()

对答案的评论

@Shafik Yaghmour很好地介绍了整个问题:因为C规范没有提及在不读取任何数据或不写入任何数据到当(n <= 0)时,它是未定义的行为.因此,任何合理的响应都应该是可以接受的,例如return NULL,不设置标志,不理会缓冲区.

@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.

关于n==1时应该发生的情况,@ Oliver Matthews回答和@Matt McNabb注释表明,考虑到n == 1的缓冲区,C规范缺乏清晰度. C规范似乎支持n == 1的缓冲区应该返回带有s[0] == '\0'的缓冲区指针,但不够明确.

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] == '\0', but is not explicit enough.

推荐答案

此行为在glibc的较新版本中有所不同,对于n == 1,它返回表示成功的s,这并非不合理的解读. 7.19.7.2 fgets函数段落 2 表示(在C99和C11中都是相同的,重点是我的):

The behavior is different in newer releases of glibc, for n == 1, it returns s which indicates success, this is not an unreasonable reading of 7.19.7.2 The fgets function paragraph 2 which says (it is the same in both C99 and C11, emphasis mine):

char * fgets(char *限制s, int n ,FILE *限制流);

char *fgets(char * restrict s, int n, FILE * restrict stream);

fgets函数读取的字符数最多少于n指定的字符数 从stream指向的流到s指向的数组.没有额外的 在换行符(保留)或文件结尾之后读取字符. 在将最后一个字符读入数组之后,立即将空字符写入.

The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. 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.

不是很有用,但不会违反标准中所说的任何内容,它将最多读取0个字符并以null终止.因此,您看到的结果看起来像是在glibc更高版本中修复的错误.显然,它也不是文件结尾,也不是第 3 段中所述的读取错误:

Not terribly useful but does not violate anything said in the standard, it will read at most 0 characters and null-terminate. So the results you are seeing looks like a bug that was fixed in later releases of glibc. It also clearly not an end of file nor a read error as covered in paragraph 3:

[...]如果遇到文件尾,并且没有字符读取到数组中,则数组的内容保持不变,并返回空指针.如果在操作过程中发生读取错误,则数组内容不确定,并返回空指针.

[...]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.

最后一种情况是n == 0,这似乎只是未定义的行为.草案C99标准部分4. Conformance 段落 2 说(强调我的):

As far as the final case where n == 0 this looks like it is simply undefined behavior. The draft C99 standard section 4. Conformance paragraph 2 says (emphasis mine):

如果违反了约束之外出现的必须"或不得"要求,则该行为是不确定的. 未定义的行为在本国际标准中通过未定义的行为"一词表示,或者省略了任何明确的行为定义.这三者之间的重点没有差异.它们都描述未定义的行为".

If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this International Standard by the words ‘‘undefined behavior’’ or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe ‘‘behavior that is undefined’’.

C11中的措词是相同的.最多不能读取 -1个字符,它既不是文件结尾也不是读取错误.因此,在这种情况下,我们没有明确的行为定义.看起来像一个缺陷,但我找不到涵盖此缺陷的任何缺陷报告.

The wording is the same in C11. It is impossible to read at most -1 characters and it is neither an end of file nor a read error. So we have no explicit definition of the behavior in this case. Looks like a defect but I cannot find any defect reports that cover this.

这篇关于fgets()返回的NULL是否与短缓冲区兼容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆