当我在规范模式下使用这段代码时:
#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”
切换到阅读
:
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”。
这是为什么?
最佳答案
正如我在 comment 中观察到的那样, 标准 I/O 包知道发生了什么并协调事情,以便在调用标准输入 (stdin
) 上的读取操作之前刷新标准输出 (stdout
) 的未决输出>) — 至少当输出和输入是“交互式设备”时,也就是终端。请注意,C 标准实际上并未强制要求同步,但大多数实现都提供了它。
read()
系统调用不知道也不关心标准 I/O 包发生了什么。它无权访问任何文件流,也无权访问这些流的任何私有(private)数据(例如缓冲输出)。因此,它无法确保在尝试读取输入之前刷新挂起的标准输出。
如果您要混合使用这两种模式,请确保在使用 read() 之前
。fflush(stdout);
或 fflush(0);
Does mixing the two modes have well defined behaviour?
这取决于你如何混合它们。如果您使用 stdout
进行输出并使用 STDIN_FILENO
进行输入,那么除了默认情况下缺少同步之外没有任何问题。如果您尝试将 stdout
操作与直接在 STDOUT_FILENO
上的操作混合,或者将 stdin
操作与直接在 STDIN_FILENO
上的操作混合,总的来说,那么你就会陷入一个受伤的世界。不要尝试这样做,因为您重视自己(或您的用户)的理智。在其他问题中,标准 I/O 库可以提前缓冲,文件描述符函数将无法看到已经读取了哪些标准 I/O。相反,在写入时,标准 I/O 库将进行缓冲,而文件描述符 I/O 则不会。
关于c - read 将 stdout 从无缓冲更改为在规范模式下缓冲的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34241929/