
系统调用
-
2023年2月17日发(作者:)[LinuxC]系统调⽤(systemcall)和库函数调⽤
(Libraryfunctions)
Linux下对⽂件操作有两种⽅式:系统调⽤(systemcall)和库函数调⽤(Libraryfunctions)。系统调⽤实际上就是指最底层的⼀个调⽤,在linux
程序设计⾥⾯就是底层调⽤的意思。⾯向的是硬件。⽽库函数调⽤则⾯向的是应⽤开发的,相当于应⽤程序的api,采⽤这样的⽅式有很多种
原因,
第⼀:双缓冲技术的实现。第⼆,可移植性。第三,底层调⽤本⾝的⼀些性能⽅⾯的缺陷。
第四:让api也可以有了级别和专门的⼯作⾯向。
1、系统调⽤
系统调⽤提供的函数如open,close,read,write,ioctl等,需包含头⽂件unistd.h。以write为例:其函数原型为size_twrite(intfd,constvoid
*buf,size_tnbytes),其
操作对象为⽂件描述符或⽂件句柄fd(filedescriptor),要想写⼀个⽂件,必须先以可写权限⽤open系统调⽤打开⼀个⽂件,获得所打开⽂件的
fd,例如fd=open(\"/dev/video\",
O_RDWR)。fd是⼀个整型值,每新打开⼀个⽂件,所获得的fd为当前最⼤fd加1。Linux系统默认分配了3个⽂件描述符值:0-standard
input,1-standardoutput,2-standarderror。
系统调⽤通常⽤于底层⽂件访问(low-levelfileaccess),例如在驱动程序中对设备⽂件的直接访问。
系统调⽤是操作系统相关的,因此⼀般没有跨操作系统的可移植性。
系统调⽤发⽣在内核空间,因此如果在⽤户空间的⼀般应⽤程序中使⽤系统调⽤来进⾏⽂件操作,会有⽤户空间到内核空间切换的开销。
事实上,即使在⽤户空间使⽤库函数来对⽂件进⾏操作,因为⽂件总是存在于存储介质上,因此不管是读写操作,都是对硬件(存储器)的操作,都
必然会引起系统调⽤。也就是说,库函数对⽂件的操作实际上是通过系统调⽤来实现的。例如C库函数fwrite()就是通过write()系统调⽤来实
现的。
这样的话,使⽤库函数也有系统调⽤的开销,为什么不直接使⽤系统调⽤呢?这是因为,读写⽂件通常是⼤量的数据(这种⼤量是相对于底层驱动
的系统调⽤所实现的数据操作单位⽽⾔),这时,使⽤库函数就可以⼤⼤减少系统调⽤的次数。
这⼀结果⼜缘于缓冲区技术。在⽤户空间和内核空间,对⽂件操作都使⽤了缓冲区,例如⽤fwrite写⽂件,都是先将内容写到⽤户空间缓冲区,
当⽤户空间缓冲区满或者写操作结束时,才将⽤户缓冲区的内容写到内核缓冲区,同样的道理,当内核缓冲区满或写结束时才将内核缓冲区内容
写到⽂件对应的硬件媒介。
2、库函数调⽤
标准C库函数提供的⽂件操作函数如fopen,fread,fwrite,fclose,fflush,fseek等,需包含头⽂件stdio.h。
以fwrite为例,其函数原型为size_tfwrite(constvoid*buffer,size_tsize,size_titem_num,FILE*pf),其操作对象为⽂件指针FILE*pf,要想写⼀
个⽂件,必须先以可写权限⽤fopen函数打开⼀个⽂件,获得所打开⽂件的FILE结构指针pf,例如pf=fopen(\"~/proj/filename\",\"w\")。
实际上,由于库函数对⽂件的操作最终是通过系统调⽤实现的,因此,每打开⼀个⽂件所获得的FILE结构指针都有⼀个内核空间的⽂件描述符
fd与之对应。同样有相应的预定义的FILE指针:stdin-standardinput,stdout-standardoutput,stderr-standarderror。
库函数调⽤通常⽤于应⽤程序中对⼀般⽂件的访问。
库函数调⽤是系统⽆关的,因此可移植性好。
由于库函数调⽤是基于C库的,因此也就不可能⽤于内核空间的驱动程序中对设备的操作。