首页 > 解决方案 > c程序中的非规范终端模式缓冲区标准输出

问题描述

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

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

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

#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);
}

所以基本上它是一个读取循环来捕获用户条目。它为“c”清除屏幕,为“b”输出字符,为“q”中断并恢复原始终端模式。

问题是:

每当我输入任何内容时,它似乎都会被缓冲,因为在我用“q”中断循环之前什么都没有发生。此时,屏幕上显示输出,如果我输入 5 次 b,我将得到 5 个 b,如果我输入 'c',屏幕将被清除。但是,只有在输入“q”之后。恢复或不恢复原始终端模式时行为相同。(之前的最后一行return

我怀疑的是:

在使代码非常短并检查所有返回之后,我倾向于认为我更改终端模式的方式可能存在问题?我尝试使用标志TCSAFLUSH和具有相同结果TCSADRAIN的函数。tcsetattr

谢谢 !:)

标签: cterminaltermiostermcap

解决方案


✅ 已解决:

好的,所以对于遇到这种情况的人来说,这很有趣,因为它让我学到了很多东西(嗯,这是一个学校项目,所以......)。

putchar在参数中使用tputs是问题所在,因为 putchar 是缓冲的,就像 printf 一样。我最终尝试了两件让我意识到的事情:fflush()tputs函数调用有效之后,问题显然与缓冲区有关。然后尝试输出到 STDERR_FILENO 并且它也解决了它,实际上 stderr 是唯一的_IONBF,所以没有缓冲。

所以我最终创建了一个只包含其中的 putchar 函数,仅write此而已。

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


推荐阅读