(转)库函数 与 系统调用

2. C 标准I/O 库函数与Unbuffered I/O 函数

现在看看C 标准I/O 库函数是如何用系统调用实现的。

fopen(3)

     调用open(2)打开指定的文件,返回一个文件描述符 (就是一个int类型的编号),
     分配一个FILE结构体,其中包含该文件的描述符、I/O 缓冲区和当前读写位置等信息,

     返回这个FILE结构体的地址。

fgetc(3)

     通过传入的FILE *参数找到该文件的描述符、I/O 缓冲区和当前读写位置,判断能否
     从I/O 缓冲区中读到下一个字符,如果能读到就直接返回该字符,否则调用
     read(2),把文件描述符传进去,让内核读取该文件的数据到I/O 缓冲区,然后返回
     下一个字符。注意,对于C 标准I/O 库来说,打开的文件由FILE *指针标识,而对于
     内核来说,打开的文件由文件描述符标识,文件描述符从open系统调用获得,在使
     用read、write、close系统调用时都需要传文件描述符。

fputc(3)

     判断该文件的I/O 缓冲区是否 空间再存放一个字符,如果 空间则直接保存在I/O 缓
     冲区中并返回,如果I/O 缓冲区已满就调用write(2),让内核把I/O 缓冲区的内容写
     回文件。

fclose(3)

     如果I/O 缓冲区中还有数据没写回文件,就调用write(2)写回文件,然后调用
     close(2)关闭文件,释放FILE结构体和I/O 缓冲区。

以写文件为例,C 标准I/O 库函数(printf(3)、putchar(3)、fputs(3))与系统调用
write(2)的关系如下图所示。

图 28.1. 库函数与系统调用的层次关系

open、read、write、close等系统函数称为无缓冲I/O                 (Unbuffered I/O )函数,因为它
                               [36]
们位于C 标准库的I/O 缓冲区的底层 。用户程序在读写文件时既可以调用C 标准I/O 库函
数,也可以直接调用底层的Unbuffered I/O 函数,那么用哪一组函数好呢?

     用Unbuffered I/O 函数每次读写都要进内核,调一个系统调用比调一个用户空间的函
      数要慢很多,所以在用户空间开辟I/O 缓冲区还是必要的,用C 标准I/O 库函数就比
      较方便,省去了自己管理I/O 缓冲区的麻烦。

     用C 标准I/O 库函数要时刻注意I/O 缓冲区和实际文件有可能不一致,在必要时需调
      用 fflush(3)。

     我 们知道UNIX 的传统是Everything is a file,I/O 函数不仅用于读写常规文件,也用
      于读写设备,比如终端或网络设备。在读写设备时通常是不希望  缓冲的,例如向代
      表网络设备的文件写数据就 是希望数据通过网络设备发送出去,而不希望只写到缓
      冲区里就算完事儿了,当网络设备接收到数据时应用程序也希望第一时间被通知到,
      所以网络编程通常直接调 用Unbuffered I/O 函数。

C 标准库函数是C 标准的一部分,而Unbuffered I/O 函数是UNIX 标准的一部分,在所 支
持C 语言的平台上应该都可以用C 标准库函数(除了  些平台的C 编译器没有完全符合C
标准之外),而只  在 UNIX 平台上才能使用Unbuffered I/O 函数,所以C 标准I/O 库函数
在头文件 stdio.h中声明,而read、write等函数在头文件unistd.h中声明。在支持
C 语言的非UNIX 操作系统上,标准I/O 库的底层可能由另外一组系统函数支持,例如
Windows 系统的底层是Win32 API,其中读写文件的系统函数是ReadFile、WriteFile。

转自:

   Linux C编程

           附录     B, GNU Free Documentation License Version 1.3, 3 November 2008. 

宋劲杉

北京亚嵌教育研究中心
<songjinshan AT akaedu DOT org>

版权 © 2008, 2009 宋劲杉, 北京亚嵌教育研究中心

 

你可能感兴趣的:(c,网络,unix,File,documentation,平台)