【问题标题】:read changes stdout from unbuffered to line buffered in canonical mode读取将标准输出从无缓冲更改为规范模式下缓冲的行
【发布时间】:2015-12-12 16:04:23
【问题描述】:

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

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

在按下q之前,我可以在控制台中阅读“Press 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;
}

在按下q 之前不显示“Press q”。

这是为什么?

【问题讨论】:

  • 标准 I/O 包知道发生了什么并协调事情,以便在调用读取操作之前刷新标准输出的挂起输出。 read() 系统调用不知道也不关心 STDOUT_FILENO 发生了什么。如果您要混合使用这两种模式,请确保在使用read() 之前先fflush(stdout);fflush(0);
  • 我敢打赌,标准输出默认是行缓冲的。在printf() 之后尝试fflush(stdout)
  • @JonathanLeffler,有道理,谢谢!,混合这两种模式是否有明确定义的行为?
  • @vlp,谢谢,是的,我知道fflush 解决了这个问题,我的问题是为什么readgetchar 之间的行为不同
  • "混合这两种模式是否有明确定义的行为?"我不会打赌。即使是这样,它也是糟糕的设计风格和维护问题,例如如果您稍后阅读代码并尝试了解发生了什么。真的有充分的理由不坚持一个吗?

标签: c getchar termios


【解决方案1】:

正如我在comment 中观察到的那样,标准 I/O 包知道正在发生什么并协调事情,以便在对标准输入(@ 987654326@) — 至少当输出和输入是“交互式设备”时,也就是终端。请注意,C 标准实际上并未强制要求同步,但大多数实现都提供了它。

read() 系统调用不知道也不关心标准 I/O 包发生了什么。它无法访问任何文件流,也无法访问这些流私有的任何数据(例如缓冲输出)。因此,它无法确保在尝试读取输入之前刷新待处理的标准输出。

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

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

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

【讨论】:

猜你喜欢
  • 2011-05-03
  • 1970-01-01
  • 1970-01-01
  • 2011-05-18
  • 2020-12-24
  • 2012-07-05
  • 2013-11-28
  • 2016-10-25
  • 1970-01-01
相关资源
最近更新 更多