【Linux】:用户缓冲区

1.前言(引出现象)

我们看一段代码,

我们运行这段代码, 

再次运行,并将打印结果重定向到文件log.txt中, 结果除了系统调用write的输出,其余输出都多打印一次。这是为什么呢?我们先了解几个知识点,再来回答这个问题。

2. C语言标准I/O函数的原理

通常,使用标准I/O的第一步是调用fopen()打开文件。

  • fopen()函数不仅会打开文件,还会创建一个缓冲区(在读写模式下会创建两个缓冲区)以及一个包含文件和缓冲区数据的结构。
  • 另外,fopen()返回一个指向该结构的指针,以便其他函数知道如何找到该结构。
  • 假设把该指针赋给一个指针变量fp,我们就说fopen()函数“打开一个流”。如果以文本模式打开该文件,就会获得一个文本流;如果以二进制模式打开文件就会获得一个二进制流。

这个结构通常包含一个指定流中当前位置的文件指示器、包含错误和文件结尾的指示器、一个指向缓冲区开始处的指针、一个文件标识符和一个计数(统计实际拷贝进缓冲区的字节数)。
一般调用这些函数,文件中的缓冲大小数据块就被拷贝到缓冲区中,缓冲区的大小引实现而异。

在初始化结构和缓冲区后,输入函数按照要求从缓冲区中读取数据,当它读取数据时,文件位置指示器被设置为指向刚读取字符的下一个字符。由于stdio.h系列的所有输入函数共用一个缓冲区,所以调用任何一个函数都将从上一次函数停止调用的位置开始。

摘抄自:《C Primer Plus》

3.缓冲区

C语言中FILE是结构体,文件类型的指针 - ostartech - 博客园 (cnblogs.com)

【Linux】分析缓冲区,刷新机制,FILE_内核模块 刷新缓冲-CSDN博客

深究标准IO的缓存 - orlion - 博客园 (cnblogs.com)

Linux 系统调用 —— fork 内核源码剖析 - 陈心朔 - 博客园 (cnblogs.com)

解释现象:

第一次程序运行,我们并没有重定向,输出的目标文件都是显示器,而显示器一般采用行缓冲策略,所以当输入换行符到缓冲区时,库函数才会调用系统接口,将用户层的缓冲区数据拷贝到内核层缓冲区。

第二次的程序运行,我们将输出的内容重定向到普通文件,普通文件的缓冲区一般采用全缓冲策略,要将缓冲区填满才会刷新缓冲区,由于printf、fprintf和fwrite输出的数据较小,不足以填满缓冲区,所以此时缓冲区的刷新是通过调用return,return调用exit刷新的。而在调用人return前,我们创建了一个子进程,子进程会继承父进程的数据和代码,为刷新的缓冲区也被继承了。所以库函数输出的内容重复了两次。      系统调用write输出的内容只打印一次,内核的缓冲区刷新机制我们暂且不讨论。

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值