1.printf函数并不会直接将数据输出到屏幕,而是先放到缓冲区中。
原因是:
解决效率和性能的问题。
比如说,printf在打印数据到屏幕上的时候不经过缓冲区,而是直接调用内核,此时内核就相当于另外一个进程,这时候就意味着想让内核帮printf做打印这件事,那么把所要打印的数据交给了内核,那么在提交这个操作以后,内核就要代表printf去执行这个操作,此时会发生阻塞,这个阻塞其实就是会发生一个从用户态到内核态的切换,切换之后内核帮printf把事情做完,然后再回复程序的执行。如果是这样的话,就相当于每次执行printf都会发生一个从用户态到内核态的切换,也就是说当前程序的执行会发生一个切换,把内核切换上来去执行,用户随便去执行printf进行打印会导致程序不断在用户态和内核态之间切换,因为从用户态到内核态的切换有很大的开销,所以频繁的切换会导致效率和性能不好。
那么,printf在打印数据到屏幕上的时候把数据先放到缓冲区,当缓冲区被放满了,这个时候再把所要打印的数据提交给内核,从用户态切换到内核态,这时候这个切换就只有一次。这样做的弊端是当执行了printf之后,所要打印的数据不能及时被打印到屏幕上,必须等缓冲区放满、或者用户强制刷新缓冲区或者程序结束才能将数据打印到屏幕上。
2.只有以下三种情况满足,才会将结果输出屏幕
(1)缓冲区满
假设现在要输出的内容有很多,当要执行printf输出内容的时候把这些内容都放到了缓冲区中,再执行printf输出内容的时候把这些内容继续放到了缓冲区中,等缓冲区的数据放满以后,才会把缓冲区中的数据提交给内核,内核调用底层的驱动程序将数据打印到屏幕上。
(2)强制刷新缓冲区
(3)程序结束时
3.示例
(1)等程序结束时将结果输出到屏幕
代码如下图所示:
退出vi编译并执行代码:
在等待3秒程序结束之后会将"hello"打印到屏幕上:
在上述例子中,程序在结束的时候刷新了一下缓冲区,先执行了printf函数把数据"hello"放到了缓冲区中,缓冲区当前无法把数据提交给内核进行打印,睡眠3秒,3秒之后程序结束,程序结束的时候缓冲区有多少数据就打印多少数据。
(2)刷新缓冲区
①通过"\n"刷新缓冲区:
代码如下所示:
退出vi编译并执行代码:
在等待3秒之后程序结束:
②通过fflush()刷新缓冲区
代码如下所示:
退出vi编译并执行代码:
在等待3秒之后程序结束:
在"hello"被打印出来之后,会刷新缓冲区,程序结束。