先看现象,printf / fprintf / fwrite 一定封装了write , 但是执行代码看到大家都是去掉\n 和close(1),库函数无法打印,write可以
你不是说的库函数封装了write,怎么打印不出来?
如果执行这两句代码你会发现程序会等待一会最后结束时打印出来,这是因为缓冲区的存在,printf把数据写入到缓冲区里面了
则printf fprintf fwrite 也一定会将数据写入进缓冲区,只不过这个缓冲区绝对不是系统级缓冲区(文件缓冲区)
为什么系统接口write能打印?
write通过文件描述符找到文件struct file 找到缓冲区写入到系统级缓冲区中,close(1)时文件关闭时它自动刷新缓冲区到磁盘中或显示器
为什么C接口看不到?
主要原因还是因为这个缓冲区一定不再操作系统内部!不是系统级别的缓冲区!
C语言提供了一个语言级 用户级缓冲区,这些C接口把数据写入到用户级缓冲区,之后close(1)关闭了文件和缓冲区,它想刷新也没地方刷新
写入用户级缓冲区的字符如果带了\n,C标准库会识别到,则立即把数据刷新到操作系统缓冲区中。
c库在合适(\n or fflush)的时候才调用wirte接口把用户级缓冲区写入到系统缓冲区中(fflush内部也是wirte)
这种刷新叫用户刷新,刷新时利用write() + 文件描述符写入到内核
尝试再次理解 exit 和 _exit
exit(1)打印了
_exit没打印
exit是C库函数,它调用fflush(stdout)刷新用户级缓冲区再调用_exit
_exit根本就不知道还有个用户级缓冲区这回事,则它不会刷新直接终止进程
目前我们认为,只要将数据刷新到了内核,数据就可以到硬件了
操作系统的缓冲区我们先不管
先来看看用户级缓冲区的刷新策略
1.写透 直接刷新
2.向显示器写是给人看的,那不就一行一刷新吗
3.向文件写入不需要每次都看一看,为了效率等缓冲区满了一气刷新
这个策略决定了什么时候调write把数据写入os中,fflush一定封装了write
问题:为什么要有这个缓冲区呢?
1、解决效率问题 ---- 用户的效率问题
这个缓冲区就像楼下的快递驿站一样,fprintf/fwrite不需要千里迢迢的去调用write,他只需要把数据放进缓冲区然后返回就这可以,如果没有缓冲区频繁调用系统接口也会有效率问题
最主要的解决你的效率问题,你不用自己坐飞机火车去西藏给人送键盘,你把东西放到驿站上楼就去打游戏就可以了。这就是为什么用C库输入输出接口很快
2、配合格式化
我们往显示器打印的是字符1 字符2 字符3 而不是数字123
你想打印数字%d a = 123 ,在调用write之前你得先把对应的数据格式化形成一个字符串给我写到一个区域里然后才能进行刷新
观察数据的流向
fprintf 会往缓冲区不断写入数据,再通过write往os里面写,写到os后C缓冲区的数据就会被清空