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

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

#include  #include  #include  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之前,我可以在控制台中阅读“按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之前不显示“按q”。

为什么是这样?

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

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

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

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

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