我正在阅读UNIX环境中的高级编程,第3版,并且误解了其中的某个部分(第145页,第5.4节“缓冲”,第5章)。
线路缓冲有两个警告。首先,缓冲区的大小 用于收集每一行的标准I / O库是固定的,因此如果可能发生I / O. 我们在写一个换行符之前填充这个缓冲区。 第二,无论何时输入 通过标准I / O库从(a)无缓冲流或(b)行缓冲流(需要从内核请求数据)请求, 所有行缓冲的输出流都被刷新。 (b)资格赛的原因 是请求的数据可能已经在缓冲区中,这不需要 要从内核读取的数据。显然,来自无缓冲的任何输入 stream,item(a),要求从内核获取数据。
我无法获得大胆的界限。我的英语不好。那么,你能为我澄清一下吗?也许以一种更简单的方式。感谢。
答案 0 :(得分:5)
所描述的阴谋背后的一点是确保在系统进入等待输入的模式之前出现提示。
如果输入流是无缓冲的,则每次标准I / O库需要数据时,都必须转到内核获取一些信息。 (那是最后一句。)那是因为标准I / O库没有缓冲任何数据,因此当需要更多数据时,它必须从内核读取。 (我认为即使是无缓冲的流也可能缓冲一个数据字符,因为它需要读取空格字符,例如,检测它何时到达%s
格式字符串的末尾;它具有放回(ungetc()
)它读取的额外字符,以便下次需要一个字符时,它会放回一个字符。但它永远不需要超过缓冲的一个字符。)
如果输入流是行缓冲的,则其输入缓冲区中可能已经存在一些数据,在这种情况下,可能不需要转到内核以获取更多数据。在这种情况下,它可能不会冲洗任何东西。如果scanf()
格式请求"%s"
并且您输入了hello world
,则会出现这种情况;它会读取整行,但第一次扫描会在hello
之后停止,而下一个scanf()
不需要转到world
字的内核,因为它已经在缓冲液中。
但是,如果缓冲区中没有任何数据,则必须要求内核读取数据,并确保刷新任何行缓冲的输出流,以便在写入时:
printf("Enter name: ");
if (scanf("%63s", name) != 1)
…handle error or EOF…
然后出现提示符(Enter name:
)。但是,如果您之前键入了hello world
并且之前只读过hello
,那么提示不一定会出现,因为world
已经在(行缓冲)输入流中等待了。
答案 1 :(得分:3)
这可以解释这一点。
让我们假设您的程序中有一个管道,并将其用于程序的不同部分之间的通信(单线程程序编写和从该单个管道读取)。
如果您写入管道的写入端,请说出字母“A”,然后调用读取操作以从管道的读取端读取。你会期望读到字母'A'。但是,读操作是对内核的系统调用。为了能够返回字母'A',必须先将其写入内核。这意味着必须刷新'A'的写入,否则它将保留在您的本地写缓冲区中,并且您的程序将被永久锁定。
结果,在调用读操作之前,刷新所有写缓冲区。这就是(b)节所说的。
答案 2 :(得分:2)
The size of the buffer that the standard I/O library is using to collect each line is fixed
。
在fgets函数的帮助下,我们连续获取该行,在此期间它将读取具有指定缓冲区大小或直到换行符的内容。
Second, whenever input is requested through the standard I/O library, it can use an unbuffered stream or line-buffered stream.
无缓冲流 - 它不会缓冲字符,定期刷新字符。
行缓冲 - 它会将字符存储到缓冲区中,然后在操作完成时刷新。
让我们不使用\n
我们打算在printf语句中打印内容,那时它将缓冲所有内容,直到我们用新行刷新或打印。就像操作完成时一样,内部刷新流缓冲区。
(b) is that the requested data may already be in the buffer, which doesn't require data to be read from the kernel
在面向行的流中,请求的缓冲区可能已经在缓冲区中,因为数据可以被缓冲,因此我们不能再次要求数据从内核读取。
(a) requires data to be obtained from the kernel.
来自无缓冲流项的任何输入,由于无缓冲流而要从内核获取的数据无法在缓冲区中存储任何内容。