C 在规范模式下,读取将标准输出从无缓冲更改为行缓冲
当我在规范模式下使用这段代码时:C 在规范模式下,读取将标准输出从无缓冲更改为行缓冲,c,getchar,termios,C,Getchar,Termios,当我在规范模式下使用这段代码时: #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
#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
之前不显示“按q”
这是为什么?正如我在a中所观察到的,标准I/O包知道发生了什么,并协调事情,以便在调用标准输入(stdin
)上的读取操作之前刷新挂起的标准输出(stdout
),至少在输出和输入是“交互式设备”的情况下,阿卡终点站。请注意,C标准实际上并不强制要求同步,但大多数实现都提供了同步
read()
系统调用不知道或不关心标准I/O包的情况。它不能访问任何文件流,也不能访问这些流的私有数据(例如缓冲输出)。因此,它无法确保在尝试读取输入之前刷新挂起的标准输出
如果要混合使用这两种模式,请确保fflush(stdout)代码>或fflush(0)使用read()
之前,先执行code>
混合这两种模式是否有明确的行为
这取决于你如何混合它们。如果您对输出使用stdout
,对输入使用STDIN\u FILENO
,除了默认情况下缺少同步之外,没有其他问题。如果您试图将stdout
操作与直接在stdout\u FILENO
上的操作相混合,或者将stdin
操作与直接在stdin\u FILENO
上的操作相混合,那么总体而言,您会受到伤害。当你重视自己(或用户)的理智时,不要尝试这样做。除其他问题外,标准I/O库可以提前缓冲,文件描述符函数将无法看到标准I/O已经读取的内容。相反,在写入时,标准I/O库将进行缓冲,而文件描述符I/O不会进行缓冲。标准I/O包知道发生了什么,并进行协调,以便在调用读取操作之前刷新挂起的标准输出输出。read()
系统调用不知道或不关心STDOUT\u FILENO发生了什么。如果要混合使用这两种模式,请确保fflush(stdout)代码>或fflush(0)在使用read()
之前,请选择code>。我敢打赌,默认情况下,stdout是行缓冲的。请在printf()
@JonathanLeffler之后尝试fflush(stdout)
,这很有意义,谢谢!,混合这两种模式是否有定义良好的行为?@vlp,谢谢,是的,我知道fflush
解决了这个问题,我的问题是read
和getchar
之间的不同行为为什么“混合这两种模式是否有定义良好的行为?”我不会打赌。即使是这样,它也是糟糕的设计风格和维护问题,例如,如果您稍后阅读代码并试图了解发生了什么。有没有一个很好的理由不坚持只读一本呢?一本有趣的书(libc特有的),还有。
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;
}