printff函数也是标准输出函数,向STDOUT_FILENO(标准输出)输出。标准io是带缓冲机制的全缓冲
标准IO的缓冲机制:
全缓冲 写满缓冲(EOF),主动冲刷flush(),数据才执行io操作(一般文件)
行缓冲 一行数据遇到“\n”,才执行io操作(一般终端)
无缓冲 立即输出到文件或终端,如fput(),write()
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello,world");
sleep(3);
return 0;
}
/*
hello,world不会先在终端(标准输出)打印,原因是printf与终端交互,是行缓冲的,
遇到“\n”才会立即冲刷缓冲区(立即打印到终端),
所以不会直接打印到屏幕,
后来程序结束,内核会来将缓冲区清空(冲刷),
所以最后打印hello,world。
*/
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello,world\n");
sleep(3);
return 0;
}
/*
在这里增加了"\n",printf函数还是行缓冲的,
遇到'\n'就立即输出到屏幕,此时缓冲区是没有数据了,这也很重要
所以你会看到屏幕先有hello,world打印,睡眠3秒再结束。
*/
测试:
第一种:
刚开始执行时
3秒后:
程序结束,内核清理
第二种:
3秒后程序结束
------------------------------------------------------------------------以上是printf为行缓冲时的相关问题。
unix高级环境编程有一句话:如果标准输出连接到终端设备,则他是行缓冲的,否则他是全缓冲的。(184页---介绍fork函数时)
#include <stdio.h>
#include <unistd.h>
char *p="I have apples\n";
int main()
{
pid_t pid;
if( write(STDOUT_FILENO,p,14)!=14 )
perror("write:\n");
printf("before fork");
if( (pid = fork())<0 ) perror("fork error\n");
else if( pid==0 )
{
printf("I am chlid\n");
}
else
{
sleep(1);
printf("I am parent\n");
}
return 0;
}
/*
结合了fork和write,先看write函数,不带缓冲,可以直接将p所指向的数据打印到屏幕,
打印的before fork,此时是在缓存区里面,并没有在终端,
后面申请的fork函数,由于sleep让main进程睡眠,后执行了,
所以先执行子进程的工作,
此时子进程拷贝的缓冲区含义已经before fork了,
所以子进程最终打印的形式为:before fork I am chlid
(为什么before...先打印,该缓冲区相当于一个队列,先进先出(可以这样理解吧))
*/
/*
将before fork后加上“\n”,子进程将不会打印"before fork"语句,
原因是‘\n’冲刷了缓冲区,子进程拷贝了已经没有数据的缓冲区了,所以子进程不会打印before fork.
*/
测试:
没有‘\n’:
有‘\n’时:
------------------------------------------------------------------------------------------以上是printf与全缓存区的联系
还有一种就是将命令行输出通过重定向到一个文件:有无”\n“文件中的数据都和没有‘\n’时一样
都会出现两次before fork。
原因:由于重定向到 文件,printf缓冲区变成了全缓冲的了,不会因为'\n'而冲刷缓冲区(只有写满或程序结束时冲刷)