1、关于标准I/O库的缓存:
在Lnix平台上,标准I/O库的作用就是为了尽可能减少使用read和write系统调用的数量。同时,在不同的系统平台上,还存在着选择最优缓冲区长度的问题,有了标准I/O库之后,所有这一切都交给标准I/O库去处理了,对程序员隐藏了不必要的复杂性。但是,标准I/O库也存在着一些比较晦涩的地方。
首先,我们知道,标准I/O有三种缓存方式:全缓存,行缓存,无缓存。对磁盘上的文件而言,一般是采用的全缓存,也就是在数据填满缓冲区或者调用了fflush()之后数据才写到磁盘上;而当流涉及的是终端,比如标准输入或标准输出时,采用的则是行缓存,即仅当输入或输出遇到一个换行符时才执行I/O操作;而无缓存则相当于直接进行write调用。我们来看下面这段代码:
printf("put some characters to stdio.");
fgets(buffer,MAXLINE,stdin);
这两行代码在标准输出上打印一行字符,然后从标准输入读入一行到buffer中。如果按照上面的解释,那么在执行第二行代码的时候我们应该是看不到
put some characters to stdio.
这一行在屏幕上的输出的,因为这里的字符串并没有以换行符'\n'结尾,但是实际上程序是先输出
put some characters to stdio.
这一行到屏幕上的。
这里,要解释清楚这个问题,就必须提到关于行缓存的一条限制:任何时候只要是通过标准I/O库从一个无缓存的流,或者一个行缓存的流得到输入数据,那么标准I/O就会刷新所有行缓存的输出流。这个地方因为我们要从标准输入stdin得到输入数据,所以虽然标准输出stdout的缓存中还没装满数据,printf也仍然会将putsome characters to stdio.这一行输出到屏幕上。默认情况下,SVR4和4.4BSD使用下列类型的缓存:
2.从流中读写一个字符:
下面这段代码取自《UNIX环境高级编程》第109页:
#include
int
main(void)
{
}
这段代码在有的机器上运行正确,而其另外的机器上运行时会出错,R. Stevens给出的解释是:
getc(),fgetc(),getchar()在中的函数原型分别是:
int
int
int
它们的返回值都是整型而非字符型,而文件结束标志EOF的通常定义为-1,如果系统使用的是有符号的字符型数据,那么程序可以正常工作;但是如果系统使用的是无符号的字符类型,那么返回的EOF保存到字符类型中之后已经不是-1了,因此程序将会出错,陷入死循环。我依稀地记得在谭老爷子的那本《C程序设计》上看到过类似的代码,所以在这里说一下。另外,无论是出错还是到达文件尾,这三个函数都返回EOF,因此必须调用ferror()或者feof()来对这两种情况进行区分。
3.打开流的限制:
我们可以像这样打开一个流:
if ((fp = fopen("filename","r+")) != NULL)
{
}
这里的"r+",或者"w+",或者"a+"都是表明我们即可以对流读,也可以对流写,但是,这是有限制的:
我猜想可能的原因是这样的,标准I/O的输入和输出操作使用的是同一缓冲区,所以必须先刷新缓冲区然后才能进行随后的操作。
个人意见,仅供参考。