c程序中的非规范终端模式缓冲区标准输出
我正在做一个学校项目(建造一个非常基本的外壳) 其想法是能够像在bash中那样进行行编辑。为此,我将终端模式更改为非规范模式,并停止echo 我编写了一个非常简单的代码来暴露我的问题(请注意,我确实检查了函数返回等。我只是在这篇文章中尽可能地简短)c程序中的非规范终端模式缓冲区标准输出,c,terminal,termios,termcap,C,Terminal,Termios,Termcap,我正在做一个学校项目(建造一个非常基本的外壳) 其想法是能够像在bash中那样进行行编辑。为此,我将终端模式更改为非规范模式,并停止echo 我编写了一个非常简单的代码来暴露我的问题(请注意,我确实检查了函数返回等。我只是在这篇文章中尽可能地简短) #包括 #包括 #包括 #包括 #包括 int main() { int ret; 半焦; 字符*术语名称; char*termcap; 结构termios termios_新; 结构termios termios\U备份; /* **初始化term
#包括
#包括
#包括
#包括
#包括
int main()
{
int ret;
半焦;
字符*术语名称;
char*termcap;
结构termios termios_新;
结构termios termios\U备份;
/*
**初始化termcap库
*/
术语_name=getenv(“术语”);
tgetent(空,术语名称);
/*
**将终端模式设置为非规范模式并关闭echo
*/
bzero(&termios_new,sizeof(struct termios));
tcgetattr(标准文件号和termios备份);
termios_new=termios_备份;
termios_new.c_lflag&=~(ICANON);
termios_new.c_lflag&=~(ECHO);
termios_new.c_cc[VMIN]=1;
termios_new.c_cc[VTIME]=0;
/*
**找零
*/
tcsetattr(标准文件号、TCSAFLUSH和termios_新文件);
/*
**获取termcap以清除特定终端上的屏幕
*/
termcap=tgetstr(“cl”,空);
/*
**循环读取以获取用户条目并清除“c”的屏幕,“b”的输出字符,以及“q”的中断
*/
而((ret=read(STDIN_FILENO,&buff,1))>0)
{
如果(buff='c')
TPUT(termcap、1、putchar);
否则如果(buff='b')
putchar(buff);
else if(buff='q')
打破
buff=0;
}
/*
**将终端模式恢复到以前的状态
*/
tcsetattr(标准文件号、TCSAFLUSH和termios\u备份);
返回(0);
}
因此,基本上,它是一个在读取时捕获用户条目的循环。它清除“c”的屏幕,“b”的输出字符,断开并恢复“q”的原始终端模式
问题是:
每当我键入任何内容时,它似乎都会被缓冲,因为在我用“q”中断循环之前,不会发生任何事情。
此时,输出显示在屏幕上,如果我键入5次b,我将得到5个b,如果我键入“c”,屏幕将被清除。
但是,只有在输入“q”之后。
恢复或不恢复原始终端模式时,行为相同。(返回之前的最后一行)
我怀疑:
在代码变得非常简短并检查所有返回之后,我倾向于认为只有我改变终端模式的方式有问题?
我使用标志TCSAFLUSH
和TCSADRAIN
尝试tcsetattr
函数,结果相同
谢谢!:)✅ 解决了的:
好吧,对于任何遇到这种情况的人来说,这非常有趣,因为它让我学到了很多东西(这是一个学校项目,所以…)
在tputs
参数中使用putchar
是一个问题,因为putchar是缓冲的,就像printf一样。
最后,我尝试了两件事情,这让我意识到:fflush()
,在tputs
函数调用可以工作之后,问题显然与缓冲区有关。
然后尝试输出到STDERR\u FILENO,它也解决了这个问题,事实上,STDERR是唯一一个\u IONBF
,所以没有缓冲
所以我最终创建了一个putchar函数,其中只有write
,就是这样。
以下是有关三种缓冲区模式的更多信息:
termios
,您希望使用setvbuf(stdin,NULL,_IONBF,0)取消缓冲stdin
代码>谢谢@DavidRanieri我希望我可以,但实际上学校项目要求我们只使用termcap库。setvbuf@Frankie_C也是如此,我不能使用termcap库中没有的外部函数。但根据您的回答,您似乎并不认为当前代码有什么不好的地方,它应该这样做吗?下面是一个与处理交换模式相关的快速回答,它的使用与交换模式相关,但提供了一些额外的行编辑技术(例如用户出错,需要退格和更正)。它可能会提供一些缺失的信息,这些信息会因坚持不懈和良好的研究努力而获得认可。
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
int ret;
char buff;
char *term_name;
char *termcap;
struct termios termios_new;
struct termios termios_backup;
/*
** Init termcap library
*/
term_name = getenv("TERM");
tgetent(NULL, term_name);
/*
** Get the terminal mode to non canonical and shut down echo
*/
bzero(&termios_new, sizeof(struct termios));
tcgetattr(STDIN_FILENO, &termios_backup);
termios_new = termios_backup;
termios_new.c_lflag &= ~(ICANON);
termios_new.c_lflag &= ~(ECHO);
termios_new.c_cc[VMIN] = 1;
termios_new.c_cc[VTIME] = 0;
/*
** Set the change
*/
tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios_new);
/*
** Get the termcap for clearing screen on the particular terminal
*/
termcap = tgetstr("cl", NULL);
/*
** Loop read to get user entries and clear screen for 'c', output char for 'b', break for 'q'
*/
while((ret = read(STDIN_FILENO, &buff, 1)) > 0)
{
if (buff == 'c')
tputs(termcap, 1, putchar);
else if (buff == 'b')
putchar(buff);
else if (buff == 'q')
break ;
buff = 0;
}
/*
** Put back the terminal mode as found before
*/
tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios_backup);
return (0);
}