繁体   English   中英

std :: iostream是如何缓冲的?

[英]How is std::iostream buffered?

一般用例

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

描述

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

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

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

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

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

因为我想听'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;
    }
}

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

问题是什么?

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

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

如果您使用的是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 ,它将抽象出底层终端类型的大部分复杂性。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM