当前位置: 首页 > news >正文

【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输出的内容只打印一次,内核的缓冲区刷新机制我们暂且不讨论。


http://www.mrgr.cn/news/15324.html

相关文章:

  • 美宜佳创新发布会圆满落幕,智慧零售战略加速推进
  • 【Java 数据结构】二叉搜索树 TreeMap 和 TreeSet 介绍
  • nodejs基于微信小程序的书籍销售系统论文源码调试讲解
  • 顺序表和链表知识点
  • 网络科学导论,网络同步与控制
  • 从 7000 余项目脱颖而出,飞轮科技《新一代实时分析数据仓库解决方案》荣获 HICOOL 2024 全球创业大赛二等奖
  • <Rust>egui学习之小部件(六):如何在窗口中添加菜单栏部件?
  • 黑神话悟空-妖怪平生录PDF
  • Go反射四讲---第三讲:如何使用反射操作函数,获取函数的相关信息?
  • VCTP(Visual Chain-of-Thought Prompting for Knowledge-Based Visual Reasoning)论文
  • 智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序(XGBoost分类器)
  • docker 安装的mysql8 设置sql_mode
  • 【数据结构-二维前缀和】力扣1314. 矩阵区域和
  • 【Java 设计模式】Callback 模式:掌握异步通信
  • Docker构建镜像时本地NuGet不存在的解决方式
  • 开源 AI 智能名片 O2O 商城小程序在社交私域中的圈层价值
  • 生成和应用patch
  • Datawhale AI夏令营第五期【深度学习进阶】深度学习基础
  • 数学基础 -- 线性代数之行阶梯形
  • netty编程之实现HTTP服务