linux stdin buffer mode是如何工作的?

tf7tbtn2  于 4个月前  发布在  Linux
关注(0)|答案(1)|浏览(85)

我知道stdoutbuffer模式是如何工作的,即:

unbuffered:无缓冲。
line buffered:当遇到换行符时刷新buffer。
block buffered:当缓冲区满时刷新。

我能理解上面的内容。
但是我对stdin缓冲区的工作原理感到困惑,我无法想象当使用三种缓冲区模式之一时会发生什么。
对于三个缓冲区模式,什么时候stdin使用哪种模式?
先谢了。

// test02.c
int main(int argc, char *argv[]){
  char ptr[20];
  scanf("%s",ptr);
  printf("%s\n",ptr);
  return 0;
}
//./test02 < log

// in this case,scanf() just read the first line of log file
// can anyone explain how the stdin buffer works?

字符串

ztyzrc3y

ztyzrc3y1#

这取决于实现--FILE I/O是如何实现的--这些模式做什么,也包括标准输出。没有任何地方 * 保证 * 设置line buffered实际上会被line buffered。
当在Linux上使用glibc时,当使用普通文件时,下溢读取数据时,读取_IO_new_file_underflow在这里被称为https://github.com/lattera/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/libio/fileops.c#L524 _IO_SYSREAD (fp, fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base);。它执行单个read系统调用。你可以按照setbuf来设置缓冲区。
然而,实际的答案要有趣得多。考虑下面的C程序,根据第一个参数,这是一个数字1,2或3,使用全缓冲,行缓冲或无缓冲的标准输入流。

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
        assert(argc >= 1);
        const int arg = atoi(argv[1]);
        const int mode = arg == 1 ? _IOFBF : arg == 2 ? _IOLBF : _IONBF;
        printf("Using mode=%d\n", mode);
        char buf[10];
        setvbuf(stdin, buf, mode, sizeof(buf));
        char ptr[20];
        scanf("%19s", ptr);
}

字符串
下面的Makefile编译程序并在strace下运行程序,使用bash here字符串输入两行。这样我们就可以看到正在进行的read系统调用:

SHELL = bash
all:
        gcc main.c
        strace -e read ./a.out 1 <<<$$'abc\ndef'
        strace -e read ./a.out 2 <<<$$'abc\ndef'
        strace -e read ./a.out 3 <<<$$'abc\ndef'


在以下方面取得成果:

$ make
gcc main.c

strace -e read ./a.out 1 <<<$'abc\ndef'
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220~\2\0\0\0\0\0"..., 832) = 832
Using mode=0
read(0, "abc\ndef\n", 10)               = 8
+++ exited with 0 +++

strace -e read ./a.out 2 <<<$'abc\ndef'
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220~\2\0\0\0\0\0"..., 832) = 832
Using mode=1
read(0, "abc\ndef\n", 10)               = 8
+++ exited with 0 +++

strace -e read ./a.out 3 <<<$'abc\ndef'
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220~\2\0\0\0\0\0"..., 832) = 832
Using mode=2
read(0, "a", 1)                         = 1
read(0, "b", 1)                         = 1
read(0, "c", 1)                         = 1
read(0, "\n", 1)                        = 1
+++ exited with 0 +++


设置_IOFBF_IOLBF只会使用缓冲区10的大小执行一个read()。这两个在阅读时工作相同。但是,_IONBF会执行一个小的read(0, .., 1),直到一个换行符。

相关问题