[英]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
聲明的函數和結構將終端設置為無緩沖。 基本上你需要禁用規范輸入,並為非規范模式設置終端。 這些鏈接可以幫助您理解兩種終端模式之間的區別:
非規范輸入 (來自libc手冊)
在非規范輸入模式下,將忽略ERASE和KILL等特殊編輯字符。 用戶編輯輸入的系統工具在非規范模式下被禁用,因此所有輸入字符(除非它們特別用於信號或流控制目的)都將完全按照鍵入的方式傳遞給應用程序。 應用程序可以根據需要為用戶提供編輯輸入的方法。
對於規范輸入 - 想想shell; 實際上,想想老式的Bourne shell,因為Bash和親戚都有命令行編輯。 你鍵入一行輸入; 如果你犯了一個錯誤,你使用擦除字符(默認是退格,通常;有時是DEL)來擦除前一個字符...對於非規范輸入 - 想想vi或vim或...你按一個字符,然后它可立即使用該程序。 在你回歸之前,你不會被耽擱。
本章介紹了為控制異步通信端口而提供的通用終端接口。 它是依賴於實現的,無論是支持網絡連接還是同步端口,還是兩者都支持
實質上,您遇到的問題不在於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.