由于标准C委员会没有标准化gets()的简单替换,它应该是什么?

chq*_*lie 19 c glibc libc language-lawyer

gets函数首先在C99中弃用,最后在C11中删除.然而,在C库中没有直接替代它.

fgets()不是替代品,因为它不会剥离最终版本'\n',这可能在文件末尾不存在.许多程序员也错了.

有一个单行代码可以删除换行符:buf[strcspn(buf, "\n")] = '\0';但它不重要,通常需要解释.它也可能效率低下.

这会适得其反.许多初学者仍然使用,gets()因为他们的老师是蹩脚的或他们的教程已经过时.

微软提出了gets_s()许多相关的函数,但它并没有默默地截断超长行,这种约束违规的行为并不简单.

BSD和GNU libc都getline在POSIX中标准化,通过realloc... 分配或重新分配缓冲区.

教初学者关于这个混乱的最佳方法是什么?

P.P*_*.P. 6

这个问题的本质就是猜测和意见.但我们可以从C99基本原理和C11标准中找到一些信息.

C99理由,当gets()被弃用,规定如下理由废除了它:

因为gets不检查缓冲区溢出,所以当它的输入不在程序员的控制之下时,使用它通常是不安全的.这导致一些人质疑它是否应该出现在标准中.委员会认为,在程序员对输入有足够控制的情况下,在特殊情况下,获取是有用和方便的,并且作为长期存在的实践,它需要标准规范.但是,一般来说,首选函数是fgets(参见§7.19.7.2).

我认为gets_s()不能被视为替代方案.因为gets_s()是可选的界面.C11实际上建议fgets()gets_s():

§K.3.5.4.1,C11草案

fgets函数允许正确编写的程序安全地处理输入行太长而无法存储在结果数组中.通常,这要求fgets的调用者注意结果数组中是否存在换行符.考虑使用fgets(以及基于换行符的任何所需处理)而不是gets_s.

因此,fgets()作为gets()ISO C中唯一真正的替代品,这就fgets()等同于gets()除了如果有缓冲空间它将在换行符中读取.那么值得引入一个新的界面,与长期和广泛使用的(fgets())一个相比有一个小的改进吗?国际海事组织,没有.

此外,许多现实世界的应用程序不仅限于ISO C.所以有机会使用扩展和POSIX getline()等作为替代品.

如果有必要在ISO C中找到编写解决方案,那么fgets()无论如何都要编写一个包装器很容易,例如my_fgets(),如果存在,则会删除换行符.

当然,fgets()向新手教学涉及解释潜在的换行问题.但IMO,并不难理解,有意学习C的人应该能够迅速掌握它.它(找到最后一个角色并替换它的角色"X")甚至可以被认为是初学者的一个好练习.

因此,鉴于上述原因,我认为ISO C中的新功能绝对没有必要作为真正的替代品gets().


R..*_*R.. 4

这个问题很大程度上需要猜测,而不是引用委员会会议纪要或其他内容,但作为一般原则,委员会(WG14)通常避免发明新的接口,而是更喜欢记录和制定严格的现有实践(例如 、 、snprintf类型long longinttypes.h) .),有时采用 C 之外的其他标准/接口定义(例如 IEEE 浮点的复杂数学、C++ 的原子模型等)。gets没有这样的替代品可供采用,可能是因为fgets通常被认为是优越的(当文件结束时没有换行符时它是无损的)。如果您确实想要直接替换,可以使用以下方法:

char buf[100];
scanf("%99[^\n]%*1[\n]", buf);
Run Code Online (Sandbox Code Playgroud)

当然,它使用起来很笨拙,尤其是当缓冲区大小可变时。

  • *委员会(WG14)通常避免发明新的界面*你在开玩笑吗?他们发明了一系列价值可疑的多字符界面。 (6认同)
  • 此代码因空行而失败(即流上的空行“\n”):如果没有匹配字符,则“%[”是*匹配失败*,因此它将不会继续到下一个说明符。 (3认同)
  • @MM:在这种情况下,您还需要一个单独的操作来空终止(未写入的)“buf”。 (2认同)
  • @chqrlie 值得指出的是 `wchar_t` 可以是 16 位,因为 Unicode 应该是 16 位。 (2认同)
  • @chqrlie:这实际上不起作用。`mbrtowc` 只能产生一个 `wchar_t`,而 `wcrtomb` 只能处理一个。`uchar16_t` 函数解除了这个 API 限制,因此它们实际上可以支持 UTF-16,但 Windows 只是有缺陷,而且非 BMP 代码点根本无法与 C mb/wc API 一起使用。(当然他们希望你忽略标准 API 并使用 WinAPI 函数......) (2认同)