我将从一些定义开始,然后继续回答您的问题。
文件:它是一个有序的字节序列。它可以是磁盘文件、程序生成的字节流(如管道)、TCP/IP 套接字、从外围设备接收或发送到外围设备(如键盘或显示器)的字节流等. 后两者是交互文件。文件通常是程序与其环境进行通信的主要方式。
流:表示数据从一个地方流向另一个,例如,从磁盘到内存,从内存到磁盘,一个程序到另一个程序等。流是数据源,可以将数据放入(写入)或取出(读取)数据。因此,它是一个用于将数据写入文件或从文件读取数据的接口,该文件可以是上述任何类型的文件。在您可以对文件执行任何操作之前,必须先打开该文件。打开文件会将其与流相关联。流由在stdio.h 标头中定义的FILE 数据类型表示。 FILE 对象(它是一个结构)包含有关与关联文件的连接的所有内部状态信息,包括文件位置指示符和缓冲信息等。 FILE 对象由输入/输出库函数在内部分配和管理,您不应该尝试创建自己的 FILE 类型的对象,库会为我们做这件事。程序应该只处理指向这些对象的指针 (FILE *) 而不是对象本身。
Buffer:Buffer是属于流的一块内存,用来临时保存流数据。当对文件进行第一次 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;
}