因为它是可选的。还有背后的人gcc
似乎认为将其包括在内是个坏主意。我不知道他们是怎么推理的,但可以在 C 标准中找到提示:
推荐做法
fgets 函数允许正确编写的程序安全地处理太长而无法存储在结果数组中的输入行。一般来说,这要求 fget 的调用者注意结果数组中是否存在换行符。考虑使用 fgets(以及基于换行符的任何所需处理)而不是 gets_s。
https://port70.net/~nsz/c/c11/n1570.html#K.3.5.4.1 https://port70.net/%7Ensz/c/c11/n1570.html#K.3.5.4.1
如果你想使用gets_s
,然后使用另一个编译器。或者编写自己的包装器,但不要调用它gets_s
因为要使其与规格完全一致是非常困难的。
C 标准是这样说的:
运行时约束
s
不得为空指针。n
既不等于零也不大于RSIZE_MAX
。读取过程中应出现换行符、文件结束符或读取错误n-1
来自标准输入的字符。
如果存在运行时约束违规,则 s[0] 将设置为空字符,并且从 stdin 读取并丢弃字符,直到读取换行符、文件结束或发生读取错误。
描述
The gets_s
函数读取的字符数最多比指定的字符数少一个n
从 stdin 指向的流,进入由 stdin 指向的数组s
。在换行符(被丢弃)之后或文件结尾之后不会读取任何其他字符。丢弃的换行符不计入读取的字符数。在读入数组的最后一个字符之后立即写入一个空字符。
如果遇到文件结尾并且没有字符读入数组,或者操作过程中发生读取错误,则s[0]
被设置为空字符,并且 s 的其他元素采用未指定的值。
这里有一件事根本没有道理。运行时约束是s
不应该是空指针。关于运行时约束违规,s[0]
应设置为零。但操作s[0] = '\0'
具有未定义的行为,如果s
是一个空指针。
这是我尝试实现它的看法,但在我看来,规范一团糟,我不相信这一点。要把它做好是很棘手的。
char *my_gets_s(char *s, size_t n)
{
if(!s) return NULL;
size_t i=0;
int ch;
for(i=0; i<n-1; i++) {
ch = fgetc(stdin);
// If end-of-file is encountered and no characters have been read into the array,
// or if a read error occurs during the operation, then s[0] is set to the null character
if(ferror(stdin) || (ch == EOF && i == 0)) {
s[0] = '\0';
return NULL;
}
// If EOF and we have read at least one character
if(ch == EOF) {
s[0] = '\0';
return s;
}
s[i] = ch;
if(ch == '\n') {
s[i] = '\0';
return s;
}
}
while ((ch = getchar()) != '\n' && ch != EOF);
s[0] = '\0';
return NULL;
}