有没有使用
通过
我们已经对应用程序进行了分析,发现性能缓慢的原因是通过
那么,是否存在使用
更新:发现了一篇有用的文章,由Paul Hsieh撰写,名为在C中处理用户输入。它是基于
另一方面,C程序员(即使是经验丰富的程序员)通常会反驳说应该使用 fgets() 作为替代方法。当然,单独使用 fgets() 并不能真正处理用户输入。除了具有奇怪的字符串终止条件(遇到 \n 或 EOF 而不是 \0),当缓冲区达到容量时所选择的终止机制是简单地中断 fgets() 操作并以 \0 终止它。因此,如果用户输入超过了预分配缓冲区的长度,则 fgets() 返回部分结果。为了处理这个问题,程序员有几种选择:1)只需处理被截断的用户输入(在提供输入时无法向用户反馈输入已被截断),2)模拟可增长的字符数组,并使用连续调用 fgets() 填充它。第一个解决方案对于变长用户输入来说几乎总是一个非常糟糕的解决方案,因为大多数情况下缓冲区不可避免地会太大,因为它试图捕获太多普通情况,而对于不寻常的情况则太小。第二个解决方案不错,但正确实现可能比较复杂。两种解决方案都无法处理 fgets() 关于 '\0' 的奇怪行为。
fread
(块I/O)而不是fgetc
(字符I/O)的getline
函数?通过
fgetc
逐个字符地读取文件会导致性能下降。我们认为,为了提高性能,可以在getline
的内部循环中使用fread
进行块读取。然而,这会产生潜在的不良影响,即可能会超出一行的末尾。至少,这将要求实现getline
来跟踪文件的“未读”部分,这需要超出ANSI C文件语义的抽象。这不是我们想自己实现的东西!我们已经对应用程序进行了分析,发现性能缓慢的原因是通过
fgetc
逐个字符地消耗大文件。相比之下,其他开销的成本实际上微不足道。我们总是按顺序从头到尾顺序阅读文件的每一行,并且可以在读取期间锁定整个文件。这可能使基于fread
的getline
更容易实现。那么,是否存在使用
fread
(块I/O)而不是fgetc
(字符I/O)的getline
函数?我们相当确定它存在,但如果不存在,我们应该如何实现它?更新:发现了一篇有用的文章,由Paul Hsieh撰写,名为在C中处理用户输入。它是基于
fgetc
的方法,但讨论了其他替代方案(从多么糟糕的gets
开始,然后讨论fgets
)。另一方面,C程序员(即使是经验丰富的程序员)通常会反驳说应该使用 fgets() 作为替代方法。当然,单独使用 fgets() 并不能真正处理用户输入。除了具有奇怪的字符串终止条件(遇到 \n 或 EOF 而不是 \0),当缓冲区达到容量时所选择的终止机制是简单地中断 fgets() 操作并以 \0 终止它。因此,如果用户输入超过了预分配缓冲区的长度,则 fgets() 返回部分结果。为了处理这个问题,程序员有几种选择:1)只需处理被截断的用户输入(在提供输入时无法向用户反馈输入已被截断),2)模拟可增长的字符数组,并使用连续调用 fgets() 填充它。第一个解决方案对于变长用户输入来说几乎总是一个非常糟糕的解决方案,因为大多数情况下缓冲区不可避免地会太大,因为它试图捕获太多普通情况,而对于不寻常的情况则太小。第二个解决方案不错,但正确实现可能比较复杂。两种解决方案都无法处理 fgets() 关于 '\0' 的奇怪行为。
留给读者的练习:为了确定调用 fgets() 时实际读取了多少字节,可以尝试像它一样扫描 '\n' 并跳过任何 '\0',同时不超过传递给 fgets() 的大小。解释为什么这对于流的最后一行是不足够的。ftell() 的哪个缺陷阻止了它完全解决这个问题?
留给读者的练习:通过在每次调用 fgets() 之间使用非零值覆盖整个缓冲区来解决确定由 fgets() 消耗的数据长度的问题。
因此,使用 fgets(),我们只能选择编写大量代码并接受与 C 库其余部分不一致的行终止条件,或者有一个任意的截止点。如果这还不够好,那我们还剩下什么? scanf() 将解析和读取混合在一起,无法分开,而 fread() 会读取字符串的末尾。简而言之,C 库没有留下任何东西。我们被迫在 fgetc() 的基础上自己编写代码。那么让我们试一试。
因此,是否存在基于 fgets
(并且不截断输入)的 getline
函数?
'\n'
预填充缓冲区并提供一种检测条件的方法来解决了这个问题。 - R.. GitHub STOP HELPING ICEfgetc
非常糟糕。在现代实现中,由于需要支持锁定,以防止多个线程访问同一个FILE
对象,使用fgetc
将非常缓慢。您可以使用getc_unlocked
(但这是一个POSIX函数,而不是标准C函数),但即使使用最佳的宏展开getc_unlocked
,fgets
搜索缓冲区\n
(即使用memchr
)的方式也比没有访问内部缓冲区时快得多。还要注意,如果您有POSIX(2008),那么已经有了getline
。 - R.. GitHub STOP HELPING ICE