std :: iostream是如何缓冲的?

时间:2012-03-31 16:36:20

标签: c++ stl iostream

一般用例

我正在尝试实现一个基本的shell。

描述

我需要读取用户输入,直到按下某些分隔符,才能执行相应的操作。这些分隔符可以是单个“a”,单个“b”或单个“c”。

输入示例如下所示(其中>是shell提示符):

> 111-222-333-444a
Ok, '111-222-333-444' entered

为什么我需要内联分隔符而不是'new-line'分隔符?

因为我想听一下键盘事件(如'向上箭头')来删除当前命令并打印最后一个命令(实现历史记录功能)。

因为我想听'tabulation'之类的键盘事件来自动完成当前命令(实现自动完成功能)。

到目前为止我有什么

到目前为止,我的代码看起来像这样:

bool done = false;
char c;
while (!done && std::cin.get(c))
{   
    switch (c)
    {
    case 'a':
        // Do something corresponding to 'a'
        done = true;
        break;

    case 'b':
        // Do something corresponding to 'b'
        done = true;
        break;

    case 'c':
        // Do something corresponding to 'c'
        done = true;
        break;

    default:
        // buffer input until a delimiter is pressed
        break;
    }
}

但是,循环似乎只有在按下“new-line”键后才会执行。此行为会终止用户输入的交互式本质。

问题是什么?

我知道std :: ostream是缓冲的,所以在发生某些事件之前内容不会写入磁盘,但是std :: istream呢。它是缓冲的吗?如果是的话,它是如何绕过这种行为我有什么选择?

此外,我已将此问题标记为“家庭作业”,因为如果不是学校的活动,这是我自己尝试做的练习,我不想只挑选一个实施所有的工作这个东西。

2 个答案:

答案 0 :(得分:7)

如果您使用的是POSIX操作系统,则可以使用termios.h中声明的功能和结构将终端设置为无缓冲。基本上你需要禁用规范输入,并为非规范模式设置终端。这些链接可以帮助您理解两种终端模式之间的区别:

  1. Noncanonical Input(来自libc手册)

      

    非规范输入模式下,将忽略ERASE和KILL等特殊编辑字符。用户编辑输入的系统工具在非规范模式下被禁用,因此所有输入字符(除非它们特别用于信号或流控制目的)都将完全按照键入的方式传递给应用程序。应用程序可以根据需要为用户提供编辑输入的方法。

  2. Canonical vs. non-canonical terminal input

      

    对于规范输入 - 想想shell;实际上,想想老式的Bourne shell,因为Bash和亲戚都有命令行编辑。你键入一行输入;如果你犯了一个错误,你使用擦除字符(默认是退格,通常;有时DEL)擦除前一个字符...对于非规范输入 - 想想vi或vim或...你按一个字符,它立即可用于该程序。在你回来之前,你不会被阻止。

  3. Description of Terminal Interface

      

    本章介绍了为控制异步通信端口而提供的通用终端接口。无论是支持网络连接还是同步端口,它都依赖于实现。

  4. 从本质上讲,您遇到的问题不在于C ++ iostream接口本身,而在于如何设置C ++ iostream接口正在读取的控制终端。因此,利用无缓冲的I / O将是一个依赖于平台的操作,并且将根据您使用的是Windows还是实际的POSIX兼容平台(这包括适用于Windows的POSIX环境,如Cygwin)而有所不同。

    如果您发现使用终端设置搞乱是一个太大的问题,您还可以查看一个跨平台的curses programming library,例如PDCurses,它将抽象出大多数复杂性基础终端类型。

答案 1 :(得分:4)

关于是否以及如何缓冲std::istream的直接问题的答案是:是的,std::istream是使用从std::streambuf派生的类的缓冲区,它定义了实际的缓冲和读取方法具体来源(或者,当使用std::ostream作为目的地时)。这是否真的有任何缓冲取决于这个具体的类,它的操作通常无法避免。

那说,这不是你的问题!问题是,如果直到新行键被击中,程序通常不会将输入发送到标准输入。这样一些行编辑可以由终端实现完成,而不必由每个程序完成。不幸的是,没有可移植的方法来改变这种情况。在POSIX上,您可以使用0tcgetattr()将标准输入流(使用文件描述符tcsetattr())转换为非规范模式。我不知道如何在非POSIX系统上实现这一点。