每个C程序员都知道,除非标准输入连接到可信源,否则没有办法安全地使用gets
函数。但是,在将其作为C标准的官方组成部分之前,为什么C语言的开发人员没有注意到这样一个明显的错误呢?而且,为什么要等到C11才将其从标准中删除,并用一个执行边界检查的函数来替换它呢?我知道通常会使用fgets
代替gets
,但后者有一个麻烦的习惯,即保留末尾的\n
符号。
每个C程序员都知道,除非标准输入连接到可信源,否则没有办法安全地使用gets
函数。但是,在将其作为C标准的官方组成部分之前,为什么C语言的开发人员没有注意到这样一个明显的错误呢?而且,为什么要等到C11才将其从标准中删除,并用一个执行边界检查的函数来替换它呢?我知道通常会使用fgets
代替gets
,但后者有一个麻烦的习惯,即保留末尾的\n
符号。
fgets
的东西来替换gets
,或者将“您是否已经完成了K&R的《C程序设计语言》中的练习?”放入缓冲区。然后人们可能会注意到使用stdin
的大多数解决方案都误用了控制台,如果从一开始就进行一致的设计,就不必如此复杂。无论如何,这个答案似乎是回答实际问题的最佳尝试。 - autistic最初,C语言出现在计算机互联网络普及之前。在当时的背景下,如果你使用C编写了一个程序并使用gets()
函数,并且抱怨因为输入太大导致程序崩溃,那么回应只会是“那就别这么做!”。“不可信输入”的整个概念几乎是无意义的——输入由操作员显式提供。
C89标准没有删除它,因为标准委员会的主要任务是将现有惯例 codify,此时gets()
肯定是现有惯例的一部分。
它在C99中被弃用,作为其删除的第一步,随后在C11中进行了删除,正如您所指出的那样。
{
size_t len = strlen (buffer);
if ((len > 0) && (buffer[len-1] == '\n'))
buffer[len-1] = '\0';
}
buffer[strcspn (buffer, "\n")] = '\n';
fgets
前端来为你完成此操作,例如 这个,显然是由 SO 中更聪明、外表更好看的成员之一编写的 :-)'\n'
:size_t len = strcspn(buffer, "\n"); buffer[len] = '\0';
- autistic无论是否将gets
加入标准都存在争议,但委员会决定当程序员对输入有足够的控制时,gets
是有用的。
以下是委员会的官方解释。
国际标准——C语言编程语言的理由 §7.19.7.7
gets
函数:由于
gets
不检查缓冲区溢出,在其输入不在程序员控制下时使用通常是不安全的。这引起了一些人对其是否应该出现在标准中的质疑。委员会决定,在那些程序员对输入有足够控制,并且作为长期存在的实践时,gets
是有用和方便的,并需要一个标准规范。然而,在一般情况下,首选函数是fgets
(参见§7.19.7.2)。
fgets
在行末添加了一个'\n'
的目的,那么这并不会那么让人烦恼。 - autistic