C语言中标准输出的缓冲机制
什么是缓冲区
缓存区是内存空间的一部分,再内存中,内存空间会预留一定的存储空间,这些存储空间是用来缓冲输入和输出的数据,预留的这部分空间就叫做缓冲区。
其中缓冲区还会根据对应的是输入设备还是输出设备分为输入缓冲区和输出缓冲区。
为什么需要缓冲?
直接操作硬件(如屏幕、磁盘)的I/O操作非常耗时。就好比如,你每次调用 printf 都直接向屏幕写入一个字符,会导致频繁的系统调用,极大降低程序效率。 缓冲机制通过将数据暂存在内存中的一块区域(缓冲区),等待满足特定条件时一次性写入目标设备,从而减少系统调用次数。
缓冲的三种模式:
全缓冲(Fully Buffered)
数据会陷入导内存的缓冲区里面,知道缓冲区满了或者我们去手动去刷新我们的缓存区,才会一次性将我们缓存区的内容写入到目标设备。
一般来说,全缓冲一般运用在文件操作的一些场景中,就好比如说我们写入文件的是时候,会使用全缓冲。还有就是重定向输出导文件的时候,stdout会从默认的行缓冲切换为全缓冲给。
#include <stdio.h>
int main() {
FILE *fp = fopen("output.txt", "w");
fprintf(fp, "Hello, World!"); // 写入缓冲区,但不会立即写入文件
// 此时文件内容为空
fflush(fp); // 手动刷新缓冲区,内容写入文件
fclose(fp); // 关闭文件时也会自动刷新
return 0;
}
注意我们代码中的这两个函数,fflush()和fclose()如果没有这两个函数的话,我们写入的内容可能会丢失。
行缓冲(Line Buffered)
在这种情况下,当在输入和输出中遇到换行符或者缓冲区满的时候,执行真正的I/O操作。
这种缓冲模式一般运用再终端输出和交互式程序中,就好比如需要及时的显示提示信息的场景(就好像自动贩卖机提示你printf(“please input your money:”))。
行缓冲一般再遇到换行符\n,缓冲区满的时候,程序正常退出的时候还有手动刷新时后触发。
#include <stdio.h>
#include <unistd.h> // 用于 sleep 函数
int main() {
printf("Start..."); // 无换行符,不刷新
sleep(2); // 等待2秒
printf("End\n"); // 遇到换行符,立即刷新,输出 "Start...End"
return 0;
}
结果:程序会等待2秒后一次性输出 Start...End
无缓冲(Unbuffered)
数据直接写入目标设备,不经过缓冲区。每次 I/O 操作都会立即生效。其实我们看名字应该就能想到时没有缓冲,那就是说,没有任何触发条件,写入操作集合生效。
一般用在标准错误流stderr和需要实时反馈的场景,好比如调试信息,关键日志。
#include <stdio.h>
int main() {
fprintf(stderr, "Error: File not found!\n"); // 立即输出
printf("This is stdout message."); // 可能延迟输出(行缓冲)
return 0;
}
结果:stderr 的输出会立即显示,而 stdout 的输出可能延迟。
如何控制缓冲模式?
我们知道了有那些缓冲模式之后,我们是不是可以去想想有哪些控制缓冲模式的方法。
我们可以使用setvbuf函数来自定义缓冲行为。
有这几个参数:
_IOFBF:全缓冲_IOLBF:行缓冲_IONBF:无缓冲
常见的问题与解决方案:
问题一:输出顺序不符合预期
就好比如这个代码:
#include "stdio.h"
int main() {
printf("A");
fprintf(stderr, "B"); // stderr无缓冲
printf("C");
}
我们可以看到他的输出结果是这样的:
BAC
这种情况就是输出顺序不符合我们的预期,我们可以使用fflush来去刷新我们的缓存区。
#include "stdio.h"
int main() {
printf("A");
fflush(stdout);
fprintf(stderr, "B"); // stderr无缓冲
printf("C");
}
这样写就可以解决这个问题了。
问题二:调试信息丢失
#include "stdio.h"
int main() {
printf("Debug info"); // 无换行符
int *p = NULL;
*p = 42; // 段错误,程序崩溃
}
首先我们来分析一下这个代码,我们的printf中没有\n所以会造成Debug info可能不会立即显示在控制台上,所以我们首先是得去使用fflush来刷新缓冲区。
然后我们定义了一个空指针,然后我们又尝试尝试通过 p 访问内存并给它赋值,但是这样肯定是有问题的,由于 p 是 NULL,这将导致段错误(Segmentation Fault),程序会崩溃。
这种情况我们也是可以使用fflush来进行刷新缓冲区的。
问题三:输入输出混合时的提示延迟
这个是这样的:

这里的我们只能先输入,然后才会提示我们的输出。
我们还是直接使用fflush去刷新缓冲区就可以了。
总结
C语言的缓冲机制是I/O高效性的核心设计,但需要开发者深刻理解其行为。
缓冲模式决定刷新时机:全缓冲看容量,行缓冲看换行,无缓冲即写即走。
手动控制是王道:在需要实时性的地方,用
fflush或stderr。跨平台注意细节:不同系统对行缓冲的实现可能有差异。
C语言中标准输出的缓冲机制的更多相关文章
- Go语言中的有缓冲channel和无缓冲channel区别
Go语言中的有缓冲channel和无缓冲channel区别 结论 ch1:=make(chan int)// 无缓冲 ch2:=make(chan int,1)// 有缓冲 无缓冲: 当向ch1中存值 ...
- GO语言练习:channel 缓冲机制
1.代码 2.运行 3.解析 1.代码 buffer.go package main import ( "fmt" "time" ) func readThre ...
- 我的Java开发学习之旅------>Java语言中方法的参数传递机制
实参:如果声明方法时包含来了形参声明,则调用方法时必须给这些形参指定参数值,调用方法时传给形参的参数值也被称为实参. Java的实参值是如何传入方法?这是由Java方法的参数传递机制来控制的,Java ...
- C++ 语言中的重载、内联、缺省参数、隐式转换等机制展现了很多优点
C++ 语言中的重载.内联.缺省参数.隐式转换等机制展现了很多优点,但是这些 优点的背后都隐藏着一些隐患.正如人们的饮食,少食和暴食都不可取,应当恰到好处. 我们要辨证地看待 C++的新机制,应该恰如 ...
- C语言中的异常处理机制
#define try if(!setjmp(Jump_Buffer)) 返回try现场后重新执行判断,所以有两次执行. http://blog.csdn.net/tian_dao_chou_qin/ ...
- 【C++】异常简述(一):C语言中的异常处理机制
人的一生会遇到很多大起大落,尤其是程序员. 程序员写好的程序,论其消亡形式无非三种:无疾而终.自杀.他杀. 当然作为一名程序员,最乐意看到自己写的程序能够无疾而终,因此尽快的学习异常处理机制是非常重要 ...
- windev中的内存机制及其与C语言中的内存指针相似性(一)
windev中的内存机制,是初入windev世界必须要越过的一道高山,以下我的理解和经验未必都对,如有错误或遗漏,以后再纠正或补充!另外,以下内容,咱先谈应用,再说对机制的认识和理解. 一.新建表单, ...
- Printf的缓冲机制
转:https://blog.csdn.net/qq_25424545/article/details/78772959 今天用fork()写程序时候,突然发现自己对Printf的缓冲机制还是有些不够 ...
- malloc实现机制、缓冲机制、文件操作、mmap虚拟地址(day06)
一.malloc的实现机制(缓冲机制) 库函数跟系统调用之间的关系 什么是缓冲? 内存分配的原理. 封装 函数A的实现代码中调用了函数B.函数B的功能是函数A主要的功能,这样就说函数A封装了函数B. ...
- CockroachDB学习笔记——[译]如何优化Go语言中的垃圾回收
原文链接:https://www.cockroachlabs.com/blog/how-to-optimize-garbage-collection-in-go/ 原作者:Jessica Edward ...
随机推荐
- 【Vue】Vue项目创建的两种方式
目录 0.提前准备 (2)webpack (3)vue全局脚手架 查看已安装版本 (4)CNPM 1.创建Vue项目的两种方式 (1)Vue2.x项目 (2)创建Vue3.x项目 (1)使用vue c ...
- Qt通用方法及类库8
函数名 //异或加密算法 static QString getXorEncryptDecrypt(const QString &str, char key); //异或校验 static uc ...
- Qt编写的项目作品32-定制化安装包工具(雨田哥作品)
一.功能特点 纯Qt编写,跨平台. 支持自定义安装目录等. 安装和卸载界面可自定义. 一键式脚本build.bat,生成安装包EXE. 兼容XP系统. 支持配置文件填充安装包信息. 指定应用程序中文名 ...
- vue:引入外部cdn报错 ‘XXX is not defined’ 及事件处理办法
框架:vue-cli(vue脚手架) 例:以cdn引入腾讯防水墙为例 前因:在html的head中引入外部cdn链接, 在vue文件中直接使用,如图 结果:如图报错 解决办法: 1. 在index.h ...
- 使用 SK Plugin 给 LLM 添加能力
前几篇我们介绍了如何使用 SK + ollama 跟 LLM 进行基本的对话.如果只是对话的话其实不用什么 SK 也是可以的.今天让我们给 LLM 整点活,让它真的给我们干点啥. What is Pl ...
- wix tool 打包官方例子
wixtoolset 和VS 插件:https://wixtoolset.org/releases/ 教学:https://www.firegiant.com/wix/tutorial/getting ...
- Linux计划任务定时备份数据
最近有项目需要定期备份mysql数据的需求,通过linux系统的crontab计划任务实现了一个简单demo,通过mysqldump命令对mysql数据进行备份. 首先新建一个脚本文件:mysqlba ...
- 第一!天翼云领跑中国边缘云laaS市场!
近日,弗若斯特沙利文(Frost & Sullivan,简称"沙利文")联合头豹研究院发布<2023年中国边缘云市场报告>,天翼云在2023H1中国边缘云Iaa ...
- 云主机CPU和内存配比:优化资源分配的关键
本文分享自天翼云开发者社区<云主机CPU和内存配比:优化资源分配的关键>,作者:每日知识小分享 随着云计算技术的快速发展,云主机已经成为了许多企业和个人用户首-选的计算解决方案.在部署和配 ...
- 云网融合再加码!天翼云SD-WAN PON来了!
近日,在中国电信集团政企信息服务事业群的组织下,天翼云科技有限公司联合中国电信上海分公司,成功举办2023年天翼云SD-WAN PON融合网关试点成果总结及推广会.会上,中国电信集团政企领导和专家,以 ...