c程序中的非规范终端模式缓冲区标准输出

c程序中的非规范终端模式缓冲区标准输出,c,terminal,termios,termcap,C,Terminal,Termios,Termcap,我正在做一个学校项目(建造一个非常基本的外壳) 其想法是能够像在bash中那样进行行编辑。为此,我将终端模式更改为非规范模式,并停止echo 我编写了一个非常简单的代码来暴露我的问题(请注意,我确实检查了函数返回等。我只是在这篇文章中尽可能地简短) #包括 #包括 #包括 #包括 #包括 int main() { int ret; 半焦; 字符*术语名称; char*termcap; 结构termios termios_新; 结构termios termios\U备份; /* **初始化term

我正在做一个学校项目(建造一个非常基本的外壳)

其想法是能够像在bash中那样进行行编辑。为此,我将终端模式更改为非规范模式,并停止echo

我编写了一个非常简单的代码来暴露我的问题(请注意,我确实检查了函数返回等。我只是在这篇文章中尽可能地简短)

#包括
#包括
#包括
#包括
#包括
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
,就是这样。

以下是有关三种缓冲区模式的更多信息:


我们的想法是能够像bash一样进行在线编辑。然后忘记
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);
}