我将从一些定义开始,然后继续回答您的问题。
文件:它是一个有序的字节序列。它可以是磁盘文件、程序生成的字节流(如管道)、TCP/IP 套接字、从外围设备接收或发送到外围设备(如键盘或显示器)的字节流等. 后两者是交互文件。文件通常是程序与其环境进行通信的主要方式。
流:它表示从一个地方到另一个地方的数据流,例如,从磁盘到内存、内存到磁盘、一个程序到另一个等。流是可以将数据放入(写入)或从(读取)中取出数据。因此,它是一个用于将数据写入文件或从文件读取数据的接口,该文件可以是上述任何类型的文件。在您可以对文件执行任何操作之前,必须先打开该文件。打开文件会将其与流相关联。流由标头中FILE
定义的数据类型表示stdio.h
。一个FILE
对象(它是一个结构)保存了有关与关联文件的连接的所有内部状态信息,包括文件位置指示符和缓冲信息等。FILE
对象由输入/输出库函数在内部分配和管理,您不应该尝试创建自己的FILE
类型对象,库会为我们完成。程序应该只处理指向这些对象的指针(FILE *
)而不是对象本身。
缓冲区:缓冲区是属于流的一块内存,用于临时保存流数据。当文件上发生第一次 I/O 操作时,malloc
会调用 并获得缓冲区。写入流的字符通常会累积在缓冲区中(在以块的形式传输到文件之前),而不是在应用程序输出它们时立即出现。类似地,流以块的形式而不是逐个字符地从主机环境中检索输入。这样做是为了提高效率,因为与内存操作相比,文件和控制台 I/O 速度较慢。
该C
库提供了三个预定义的文本流 ( FILE *
),它们在程序启动时打开并可供使用。它们是stdin
(标准输入流,程序的正常输入源),stdout
(标准输出流,用于程序的正常输出)和stderr
(标准错误流,用于错误消息和程序发出的诊断信息)。这些流是缓冲的还是非缓冲的是实现定义的,而不是标准要求的。
GCC
提供三种类型的缓冲——无缓冲、块缓冲和行缓冲。无缓冲意味着字符在写入后立即出现在目标文件中(对于输出流),或者从文件中逐个字符地读取输入,而不是读取块(对于输入流)。块缓冲意味着字符保存在缓冲区中并作为块写入或读取。行缓冲意味着字符仅保存到换行符写入缓冲区或从缓冲区读取。
stdin
并且stdout
当且仅当可以确定它们不引用交互式设备时才进行块缓冲,否则它们是行缓冲的(对于任何流都是如此)。stderr
默认情况下总是无缓冲的。
标准库提供了改变流默认行为的函数。您可以使用fflush
强制数据从输出流缓冲区(fflush
输入流未定义)。您可以使用该setbuf
函数使流无缓冲。
现在,让我们来回答您的问题。
未标记的问题:是的,因为stdout
通常指的是显示终端,除非您使用>
运算符进行输出重定向。
Q1:它等待是因为stdout
在引用终端时缓冲了换行符。
Q2:字符被缓冲在分配给stdout
流的缓冲区中。
Q3:打印流程为:内存-->stdout
缓冲区-->显示终端。操作系统也控制了内核缓冲区,数据在出现在终端之前会通过这些缓冲区。
Q4:stdout
指标准输出流,通常是终端。
最后,这是一个示例代码,用于在我完成答案之前进行实验。
#include <stdio.h>
#include <limits.h>
int main(void) {
// setbuf(stdout, NULL); // make stdout unbuffered
printf("Hello, World!"); // no newline
// printf("Hello, World!"); // with a newline
// only for demonstrating that stdout is line buffered
for(size_t i = 0; i < UINT_MAX; i++)
; // null statement
printf("\n"); // flush the buffer
return 0;
}