read 将 stdout 从无缓冲更改为在规范模式下缓冲的行
read changes stdout from unbuffered to line buffered in canonical mode
当我在规范模式下使用这段代码时:
#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 包知道发生了什么并协调事情,以便在调用之前刷新到标准输出 (stdout
) 的未决输出标准输入 (stdin
) 上的读取操作——至少当输出和输入是 'interactive device',也就是终端时。请注意,C 标准实际上并未强制要求同步,但大多数实现都提供了它。
read()
系统调用不知道也不关心标准 I/O 程序包发生了什么。它无权访问任何文件流,也无权访问这些流的任何私有数据(例如缓冲输出)。因此,它无法确保在尝试读取输入之前刷新挂起的标准输出。
如果您要混合使用这两种模式,请确保在使用 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 不会。
当我在规范模式下使用这段代码时:
#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
切换到 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 "。
这是为什么?
正如我在 stdout
) 的未决输出标准输入 (stdin
) 上的读取操作——至少当输出和输入是 'interactive device',也就是终端时。请注意,C 标准实际上并未强制要求同步,但大多数实现都提供了它。
read()
系统调用不知道也不关心标准 I/O 程序包发生了什么。它无权访问任何文件流,也无权访问这些流的任何私有数据(例如缓冲输出)。因此,它无法确保在尝试读取输入之前刷新挂起的标准输出。
如果您要混合使用这两种模式,请确保在使用 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 不会。