We can see that the default for this system is to have standard input and standard
output line buffered when they’re connected to a terminal.
从这个例子:
#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
即使将std[in,out]连接到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
书中的例子使用了4个操作系统(solaris,openBSD,Linux和macos)的特定于操作系统的宏,所以我的操作系统也在其中。
编辑:在 my 机器中,宏和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>-
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
1条答案
按热度按时间vuv7lop31#
上一点:
正如注解中所述,帮助函数可能无法准确地描述系统文件缓冲的真实的默认状态。
也就是说,文件缓冲是实现定义的,从C11 N1570:
§7.21.3
3 - [...] * 当流被完全缓冲时,当缓冲区被填满时,字符将作为块传输到主机环境或从主机环境传输。如果流是行缓冲的,则当遇到换行符时,字符将作为块传输到主机环境或从主机环境传输。此外,当缓冲器被填充时,当在未缓冲流上请求输入时,或者当在需要从主机环境传输字符的行缓冲流上请求输入时,字符旨在作为块被传输到主机环境。对这些特性的支持是实现定义的,可能会通过setbuf和setvbuf函数受到影响。*
7 - * 在程序启动时,三个文本流是预定义的,不需要显式打开-标准输入(用于阅读常规输入),标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。初始打开时,标准错误流未完全缓冲;当且仅当标准输入和标准输出流可以被确定为不涉及交互式设备时,该标准输入和标准输出流被完全缓冲。
我强调的是。
根据我在Linux和MacOS上的个人经验,
stdin
和stdout
在与终端关联时是行缓冲的,否则是全缓冲的,而stderr
是无缓冲的,所以这与书中描述的行为一致,显然不同于您的特定情况,但同样,这是实现定义的。我不会说这本书是错的,但 * 默认行为 * 绝对可以解释为这是规范,并始终适用于上述系统。