【发布时间】:2021-06-07 08:50:06
【问题描述】:
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 结构的实现:
/* The possibilities for the third argument to `setvbuf'. */
#define _IOFBF 0 /* Fully buffered. */
#define _IOLBF 1 /* Line buffered. */
#define _IONBF 2 /* No buffering. */
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
【问题讨论】:
-
default for this system-- 您运行的系统与书中的系统相同吗?您是否希望 您的 系统默认为行缓冲? -
@Oka 查看编辑,linux(我的操作系统)使用正确的 FILE 结构实现,就像本书一样。
-
在您的实现中,
_IONBUF等是单个位吗?我可以看到一个使用多个位的合理实现,这会使您的辅助函数受到怀疑。 -
@WilliamPursell 这些宏_IO* 定义在
<stdio.h> -
为什么你甚至期望像
return (fp->_IO_buf_end - fp->_IO_buf_base)这样的东西能正常工作?没有“标准”FILE结构,在某些系统上您甚至无法访问其成员。