fgets函数规范不一致

问题描述 投票:0回答:1

标准函数

fgets
在即将推出的C23标准中是这样指定的:

7.23.7.2 fgets 函数

剧情简介

    #include <stdio.h>
    char *fgets(char * restrict s, int n, FILE * restrict stream);

fgets
函数最多将
n
指定的字符数从
stream
指向的流中读取到
s
指向的数组中。在换行符(保留)之后或文件结尾之后不会读取任何其他字符。在读入数组的最后一个字符后立即写入空字符。

退货

如果成功,

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

除了 C99 中添加的

restrict
关键字之外,此规范自原始 ANSI-C 文档以来没有任何变化。

n
指定的类型为
int
,这与采用数组长度或对象计数(类型为
size_t
)的所有其他 C 库函数不一致。如果不潜在地破坏使用指向
fgets
的函数指针或为
n
传递负值的程序,则无法解决此问题。
fread
fwrite
,以及许多其他标准函数,在原始 Unix 文档中过去将其数字参数和返回值指定为
int
,但在 ANSI-C 之前进行了更改,这就引出了一个问题:为什么
fgets
未包含在本次更新中,那么是否有任何令人信服的理由以不同方式对待
fgets()

此外,有些案例似乎没有指定的行为:

  • 如果
    n <= 1
    fgets()
    应该返回
    s
    而不尝试从流中读取吗?
  • 如果
    n == 1
    ,尽管没有字符被读入数组,但是否应该将
    s[0]
    设置为空字符?
  • if
    n <= 0
    ,我们可以为
    s
    传递一个空指针吗?
arrays c language-lawyer fgets
1个回答
0
投票

关于

n <= 1
的行为:

在本规范的上下文中没有“成功”的正式定义,唯一想到的失败情况与从流中读取并收到错误或到达文件末尾有关,这两种情况都在规范中解决. 由于

fgets()

 最多读取比 
n
 指定的字符数少 1 个字符,因此它不应该读取 
n <= 1
的任何字符,因此不会尝试从流中进行任何输入。因此,在这种情况下,
fgets()
应返回
s
似乎未指定是否必须修改 

s

以及如果

s[0]
则将
n == 1
设置为空字符,尽管我有权访问其源代码的所有 C 库都以这种方式运行。
由于存在这个潜在问题,似乎建议避免使用低于 

fgets()

的值来调用

2
作为参数
n
注意

snprintf

也有类似的问题:


7.23.6.5

snprintf 函数


剧情简介

#include <stdio.h> int snprintf(char * restrict s, size_t n, const char * restrict format, ...);

snprintf

函数等同于

fprintf
,只不过输出被写入数组(由参数
s
指定)而不是流中。如果
n
为零,则不写入任何内容,并且
s
可能是空指针。否则,超出第
n-1
st 的输出字符将被丢弃,而不是写入数组,并在实际写入数组的字符末尾写入空字符。如果复制发生在重叠的对象之间,则行为未定义。

退货

snprintf

函数返回如果

n
足够大则已写入的字符数,不包括终止空字符,如果发生编码错误则返回负值。因此,当且仅当返回值均为非负且小于
n
时,空终止输出才被完全写入。

如果实际上没有将任何字符写入数组,则句子
and a null character is write at the end of the characteracted into the array

有点含糊,要么是因为输出为空,要么因为它已被完全丢弃。 尽管存在这种歧义,但似乎不可能争论给定空格式字符串的

snprintf

可能不会在

s
中生成空字符串,前提是
n
不为零。
对于 

snprintf

的情况,使用更精确的

fgets
n == 1
规范会很有帮助,确保将
s[0]
设置为空字符。
    

© www.soinside.com 2019 - 2024. All rights reserved.