std :: iostream是如何缓冲的?

aut*_*hir 21 c++ iostream stl

一般用例

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

描述

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

输入示例如下所示(>shell提示符在哪里):

> 111-222-333-444a
Ok, '111-222-333-444' entered
Run Code Online (Sandbox Code Playgroud)

为什么我需要内联分隔符而不是"新行"分隔符?

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

因为我想听'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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,循环似乎只有在按下"新行"键后才会执行.此行为会终止用户输入的交互式本质.

问题是什么?

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

此外,我已将此问题标记为"家庭作业",因为如果不是学校的练习,这是我自己尝试做的练习,我不想只挑选一个实现所有这些东西的库.

Jas*_*son 7

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

  1. 非规范输入(来自libc手册)

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

  2. 规范与非规范终端输入

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

  3. 终端接口说明

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

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

如果你发现搞乱终端设置太麻烦了,你也可以查看一个跨平台的curses编程库,比如PDCurses,它将抽象出底层终端类型的大部分复杂性.


Die*_*ühl 5

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

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