You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何连接终端时stdin、stdout未采用行缓冲?与《UNIX高级编程》描述不符的技术疑问

终端下stdin/stdout缓冲模式与《UNIX高级编程》描述不符的疑问

我最近在验证《UNIX高级编程》里关于标准IO缓冲的描述时遇到了困惑:书中明确提到,当标准输入(stdin)和标准输出(stdout)连接到终端时,系统默认应为行缓冲模式。为了验证这一点,我直接运行了书中提供的示例代码:

#include <stdio.h>
#include <stdlib.h>
long buffer_size(FILE *fp) {
    return (fp->_IO_buf_end - fp->_IO_buf_base);
}
int is_linebf(FILE *fp) {
    return (fp->_flags & _IOLBF);
}
int is_unbf(FILE *fp) {
    return (fp->_flags & _IONBF);
}
void stream(const char *name, FILE *fp) {
    printf("stream = %s, ", name);
    if (is_unbf(fp)) {
        printf("unbuffered");
    } else if (is_linebf(fp)) {
        printf("line buffered");
    } else {
        printf("fully buffered");
    }
    printf(", buffer size = %ld\n", buffer_size(fp));
}
int main() {
    FILE *fp;
    fputs("enter any character: ", stdout);
    if (getchar() == EOF) {
        perror("getchar error");
    }
    fputs("one line to standard error\n", stderr);
    stream("stdin", stdin);
    stream("stdout", stdout);
    stream("stderr", stderr);
    if ((fp = fopen("/etc/passwd", "r")) == NULL) {
        perror("fopen error");
    }
    if (fgetc(fp) == EOF) {
        perror("fgetc error");
    }
    stream("/etc/passwd", fp);
    exit(0);
}

但运行结果却和书中描述完全不符:

$ ./a.out
enter any character: a
one line to standard error
stream = stdin, fully buffered, buffer size = 1024
stream = stdout, fully buffered, buffer size = 1024
stream = stderr, unbuffered, buffer size = 1
stream = /etc/passwd, fully buffered, buffer size = 4096

明明我的stdin和stdout已经连接到TTY终端,但它们却处于全缓冲状态,而非书中所说的行缓冲。现在我有点拿不准:是书中的描述存在误差,还是我遗漏了某些关键细节?

我的系统信息如下:

uname -a : Linux 5.8.0-44-generic #50-Ubuntu SMP Tue Feb 9 06:29:41 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

书中的示例针对Solaris、OpenBSD、Linux和macOS这4种操作系统使用了特定于系统的宏,我的Linux系统也在覆盖范围内。

另外,我特意查看了本地系统中相关宏和FILE结构体的实现:

<stdio.h>中的缓冲模式定义:

/* The possibilities for the third argument to `setvbuf'. */
#define _IOFBF 0 /* Fully buffered. */
#define _IOLBF 1 /* Line buffered. */
#define _IONBF 2 /* No buffering. */

<struct_FILE.h>中的_FILE结构体实现:

struct _IO_FILE {
    int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
    /* The following pointers correspond to the C++ streambuf protocol. */
    char *_IO_read_ptr; /* Current read pointer */
    char *_IO_read_end; /* End of get area. */
    char *_IO_read_base; /* Start of putback+get area. */
    char *_IO_write_base; /* Start of put area. */
    char *_IO_write_ptr; /* Current put pointer. */
    char *_IO_write_end; /* End of put area. */
    char *_IO_buf_base; /* Start of reserve area. */
    char *_IO_buf_end; /* End of reserve area. */
    /* The following fields are used to support backing up and undo. */
    char *_IO_save_base; /* Pointer to start of non-current get area. */
    char *_IO_backup_base; /* Pointer to first valid character of backup area */
    char *_IO_save_end; /* Pointer to end of non-current get area. */
    struct _IO_marker *_markers;
    struct _IO_FILE *_chain;
    int _fileno;
    int _flags2;
    __off_t _old_offset; /* This used to be _offset but it's too small. */
    /* 1+column number of pbase(); 0 is unknown. */
    unsigned short _cur_column;
    signed char _vtable_offset;
    char _shortbuf[1];
    _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
struct _IO_FILE_complete {
    struct _IO_FILE _file;
#endif
    __off64_t _offset;
    /* Wide character stream stuff. */
    struct _IO_codecvt *_codecvt;
    struct _IO_wide_data *_wide_data;
    struct _IO_FILE *_freeres_list;
    void *_freeres_buf;
    size_t __pad5;
    int _mode;
    /* Make sure we don't get into trouble again. */
    char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
};

FILE被定义为:typedef struct _IO_FILE FILE


内容的提问来源于stack exchange,提问作者milanHrabos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 10:37:38