当我在规范模式中使用这段代码时:
#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
被按下。
为什么会这样?
答案 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不会被激活。