读取将stdout从unbuffered更改为以规范模式缓冲的行

时间:2015-12-12 16:04:23

标签: c getchar termios

当我在规范模式中使用这段代码时:

#include <stdio.h>
#include <termios.h>
#include <unistd.h>

static struct termios newt;
static struct termios oldt;

static void kb_fini(void)
{
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
}

void kb_init(void)
{
    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= (tcflag_t)~(ICANON | ECHO | ISIG);
    newt.c_cc[VMIN] = 1;
    newt.c_cc[VTIME] = 0;
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    atexit(kb_fini);
}

int main(void)
{
    int c;

    kb_init();
    printf("Press q ");
    c = getchar();
    if (c == 'q') {
        printf("q was pressed\n");
    }
    return 0;
}

我能够阅读&#34;按q&#34;在按q

之前在控制台中

切换为read

int main(void)
{
    char c;

    kb_init();
    printf("Press q ");
    read(STDIN_FILENO, &c, 1);
    if (c == 'q') {
        printf("q was pressed\n");
    }
    return 0;
}

没有显示&#34;按q&#34;直到q被按下。

为什么会这样?

1 个答案:

答案 0 :(得分:2)

正如我在comment中观察到的那样,标准I / O包知道发生了什么并协调事物,以便在调用读操作之前刷新标准输出(stdout)的挂起输出。标准输入(stdin) - 至少当输出和输入是交互式设备时,即终端。请注意,C标准实际上并未规定同步,但大多数实现都提供了同步。

read()系统调用并不了解或关心标准I / O包的内容。它无法访问任何文件流,也无法访问这些流专用的任何数据(例如缓冲输出)。因此,它无法确保在尝试读取输入之前刷新挂起的标准输出。

如果您要混用这两种模式,请在使用fflush(stdout);之前确保fflush(0);read()

  

混合这两种模式是否有明确定义的行为?

这取决于你如何混合它们。如果您使用stdout作为输出而使用STDIN_FILENO作为输入,则默认情况下除了缺少同步之外没有问题。如果您尝试将stdout操作与STDOUT_FILENO上的操作直接混合,或stdin操作直接在STDIN_FILENO上进行操作,那么您将面临一个受伤的世界。不要尝试这样做,因为你重视自己(或用户的)理智。在其他问题中,标准I / O库可以提前缓冲,文件描述符函数无法查看已经读取的标准I / O.相反,在写入时,标准I / O库将缓冲并且文件描述符I / O不会被激活。