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;
}