C11中的gets()等价于什么?

22

来自 cplusplus.com

最新版的C标准(2011)已经从其规范中明确删除了此函数。

C++中的此函数已被弃用(从2011年标准开始,遵循C99+TC3)。

我只是想知道C11标准中替代gets()的方法是什么?

4个回答

16

在C11中,gets已被替换为具有以下声明的gets_s

char *gets_s(char *str, rsize_t n);
该函数将最多读取 n-1 个字符从 stdin*str 中,以避免 gets 内在的缓冲区溢出漏洞。此外,fgets 函数也是一种选择。根据http://en.cppreference.com/w/c/io/gets

gets() 函数不执行边界检查,因此此函数极易受到缓冲区溢出攻击。除非程序在限制输入的环境中运行,否则不能安全使用此函数。因此,在 C99 标准的第三次勘误中已将该函数弃用,并在 C11 标准中将其完全删除。应使用 fgets()gets_s() 来替换。

绝对不要使用 gets()

鉴于 gets_s 在标准扩展中定义,只是可选实现的,您应该使用 fgets 来编写程序。如果您在 stdin 上使用 fgets,那么您的程序也将在早期版本的 C 中编译。但请记住行为上的差异:当 gets_s 读取 n-1 个字符后,它会继续读取直到达到新行或文件结尾,而将输入丢弃。因此,使用 gets_s 您总是在读取整行,即使只有部分内容可以返回到输入缓冲区中也是如此。


7
需要注意的是,如果实现不定义__STDC_LIB_EXT1__,则gets_s是可选的,可以不出现;如果实现定义了__STDC_LIB_EXT1__,则需要定义__STDC_WANT_LIB_EXT1__为1,否则在相应的头文件中是否包含K附录中的函数是由实现定义的。 - Daniel Fischer
6
应该使用fgets函数。gets_s 函数是一个可选的接口,仅存在于 Windows 平台,并且仅因政治原因在标准中被提及。除 Microsoft 以外的大部分人都认为 _s 接口是误导性和有害的。据报道,某些或所有 _s 接口的标准行为甚至与唯一现有的实现(Microsoft 的实现)不同,使得它们的使用更加有害。 - R.. GitHub STOP HELPING ICE
1
我怀疑您误解了gets_s的行为。就像fgets一样,它最多读取n-1个字符。不同之处在于,gets_s遇到换行符时会停止读取。标准中没有任何指示表明它会在n-1之后继续读取。不要将标准版本与C11之前存在的各种非标准实现混淆。 - Lundin
@Joni 是的,我有实际的C11标准,而不仅仅是草案。为了参考,我会在我所做的“信息性”答案中包含这段文字。 - Lundin
@Lundin:另一个主要区别是gets_s()从缓冲区中省略了换行符,因此避免了需要扫描新接收的字符串以查找并消除它的需要吗? - supercat
显示剩余3条评论

9
其他人已经回答了这个问题。为了完整起见,这是C标准的建议:
ISO9899:2011 K.3.5.4.1/6
推荐做法 fgets函数允许编写正确的程序安全地处理输入行,以便在结果数组中存储过长的行。一般来说,这要求fgets的调用者注意结果数组中换行符的存在或不存在。考虑使用fgets(以及基于换行符的任何必要处理)代替gets_s。
因此,尽可能使用fgets。
编辑
gets_s的行为被指定为:
ISO9899:2011 K.3.5.4.1/4
描述 gets_s函数从指向stdin的流中读取最多比n指定的字符数少一个字符,并将其读入指向s的数组中。在新行字符(被丢弃)或文件结尾之后,不会读取其他字符。被丢弃的新行字符不计入读取的字符数。空字符立即写入到读取的最后一个字符所在的数组位置之后。 如果在操作期间遇到文件结尾并且没有将任何字符读入数组中,或者在操作期间发生读取错误,则将s[0]设置为空字符,并且s的其他元素采用未指定的值。

4
请注意,如果在前 n-1 个字符内既没有换行符又没有 EOF,则 gets_s() 函数将报告约束违规,读取超长的行是错误的。请确保输入不会超过缓冲区大小,以避免这种情况的发生。 - Jonathan Leffler

6

4
根据man 3 getsfgets函数。

C11标准中的gets等效函数是gets_s,尽管从技术上讲它应该与fgets(..., stdin)相同; - Lundin
1
“出于政治原因添加的可选附件”几乎不属于“C11标准”。你无法在任何地方找到符合C11标准的_s函数版本,因为没有人计划实现它们。 - R.. GitHub STOP HELPING ICE
2
@R.. C11的附录K是规范性的,尽管不强制实现。这在实践中意味着,C实现不再包含具有与标准冲突的行为的奇怪、非标准的gets_s函数。我也敢打赌GCC将实现这些函数:那个编译器只喜欢可选的、多余的、无意义的功能。但出于兼容性原因,我建议使用fgets()。 - Lundin
1
由于它们是库函数,所以它们不在GCC的范围之内。如果你指的是glibc,我相信维护者已经明确表示不感兴趣添加它们了。此外,我甚至不确定非标准版本的函数是否不符合规范,除非实现通过适当的预定义宏来广告(支持Annex K)。如果微软的函数确实与标准不同,我认为它们被更改的机会大约为零;他们似乎根本不关心符合性。 - R.. GitHub STOP HELPING ICE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接