【问题标题】:Using setvbuf() with STDIN stream将 setvbuf() 与 STDIN 流一起使用
【发布时间】:2011-08-18 02:18:30
【问题描述】:

我正在编写一个小型 C 程序,它必须接受大于 4096 字节的输入流。

我确实在这里找到了推荐使用 setvbuf() 的帖子:

Making fgets issue longer read() calls on linux

我仍然很难让它工作 - 这是我正在努力解决的部分代码:

int main(void) 
{ 
#define MAX_STRING_SIZE 7168

char input_string[MAX_STRING_SIZE];

printf( "Input: " );

setvbuf( stdin, NULL, _IONBF, 0 );

fgets( input_string, MAX_STRING_SIZE-1, stdin );

printf( "\n" );
printf( "%s", input_string );
} 

有没有人成功增加这个输入缓冲区?

我的环境:带有 build-essential 软件包的 Ubuntu 10.10

谢谢!

【问题讨论】:

  • 如果你使用fread()而不是fgets()会怎样。
  • 我刚试过 fread() 但它似乎有同样的问题。当提示输入时,我只能将 4096 字节粘贴到终端窗口中。
  • 那么应用程序要求将数据“粘贴”到终端中?如果使用文件重定向< 操作,fread() 甚至fgets() 应该没问题。当然,您可以逐个字符地读取数据。它应该可以正常工作。

标签: c stream stdin


【解决方案1】:

现在您正在使用_IONBF,这意味着没有缓冲。改用 _IOFBF 可能是一个好的开始(即 full 缓冲)。要增加缓冲区大小,您还需要将大缓冲区大小指定为第四个参数,例如:

setvbuf(stdin, NULL, _IOFBF, 16384);

这会动态分配缓冲区空间。根据具体情况,您可能希望将缓冲区传递给它:

char mybuffer[32768];

setvbuf(stdin, mybuffer, _IOFBF, sizeof(mybuffer));

【讨论】:

  • 嗯 - 我已将行更改为:“setvbuf(stdin, NULL, _IOFBF, 16384);”但它似乎仍然有一个硬限制,即 4,096。这段代码提示输入,我只是试图将 4,261 个字符的字符串粘贴到终端窗口中。字符串仍然在 4,096 标记处被切断。
  • @Nate:猜测一下,这无关紧要。听起来您遇到了终端窗口行编辑器中内置的缓冲区限制。 setvbuf 只更改标准库中内置的缓冲区。当您从终端读取数据时,它将从终端的 4096 字节缓冲区复制到您指定的缓冲区中——但更改库中的缓冲区不会影响终端内置的 on。您也许能够更改终端的缓冲区大小,但如果是这样,它可能会使用ioctl 之类的东西。
  • @Jerry:我知道我正在打一些缓冲区,但我同意我不知道哪个缓冲区(:当我在我的 Ubuntu 终端窗口中的普通命令提示符下我可以粘贴完整的 4261 字节,只有当我执行我的 C 程序并要求输入时,它才会将我限制为 4096。
  • @Nate:主要的一点是它几乎肯定不是setvbuf 控制的那个,所以你不能用setvbuf 做任何事情都可能有帮助。
  • @Jerry:非常感谢您帮助确认这一点。我正在尝试修改一些现有代码。我必须重新编写更多代码才能从文件中读取。
【解决方案2】:

我过去曾尝试过缓冲区大小,但发现增加它没有什么好处。如果您使用任何更高级别的输入函数,如 fgets(或更糟的是,fgetcfscanf),则将花费足够的时间搜索分隔符或函数调用或解析开销,而不是 read 的数量系统调用真的没那么重要,只要缓冲区至少为 1kb 左右。另一方面,如果您一次读取大块(通过fread),则实现应该足够聪明,可以完全跳过缓冲并直接读取调用者提供的缓冲区。因此,我通常认为setvbuf 是无用的,尽管可能是无害的微优化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 2016-12-19
    • 2013-08-18
    • 1970-01-01
    • 2019-10-29
    • 1970-01-01
    相关资源
    最近更新 更多