在写程序的过程中,像MFC,VC++这些编程,都会涉及到函数的调用,有库函数也有系统函数,下面看一看它们的区别!!
系统调用(system call)和库函数调用(Library function call)的区别?
理解库函数的区别和系统调用,首先是kernel mode和user mode这两个模式是这两种函数工作时的空间不同。
一、系统调用:
系统调用实际上是指底层的一个调用,就是内核提供的、功能十分强大的一系列的函数。这些系统调用是在内核中实现的。是操作系统为用户态运行的进程和硬件设备(如CPU、磁盘、打印机等)进行交互提供的一组接口,即就是设置在应用程序和硬件设备之间的一个接口层。可以说是操作系统留给用户程序的一个接口。
例如linux内核是单内核,结构紧凑,执行速度快,各个模块之间是直接调用的关系。放眼整个linux系统,从上到下依次是:用户进程->系统调用接口->linux内核子系统->硬件。linux内核包括了系统调用接口和内核子系统两部分。或者从下到上:物理硬件->OS内核->OS服务->应用程序。这里的OS起到了“承上启下”的关键作用,向下管理物理硬件,向上为操作系统服务和应用程序提供接口,这里的接口就是系统调用了。操作系统提供的少部分系统调用都是由C和汇编混合编写实现的,其接口用C来定义,具体实现则是汇编,这样的好处是执行效率高,而且极大的方便了上层的调用。
在linux程序设计就是底层调用的意思,面向的是硬件。例如open,read,read等都是用于底层文件的访问(low-level file access),例如在驱动程序中对文件的直接访问;系统调用是操作系统相关的,因此一般没有跨操作系统的可移植性;系统调用发生在内核空间,因此如果用户在用户空间的一般应用程序中使用系统调用来进行文件的操作,会有用户空间到内核空间的切换开销。事实上,即使在用户空间是用库函数来对文件进行操作,必然会引起系统的调用,因为文件总是存储在介质上的,不管是读还是写,都是对硬件存储器的操做,必然引起系统调用。例如C库函数fwrite和fread就是通过read和write系统函数来实现的。这样的话,使用库函数也有系统调用的开销,为什么不直接使用系统调用呢:这是因为读写文件通常是大量的数据(这种大量是相对于底层驱动的系统调用所实现的数据操作单位而言),这时,使用库函数就可以大大减少系统调用的次数(系统调用是一种中断服务机制,需要提出申请占用CPU或某些资源来对硬件访问与操做,如I/O操作,文件的读取更新等)。这一结果又缘于缓冲区技术。在用户空间和内核空间,对文件操作都使用了缓冲区,例如用fwrite写文件,都是先将内容写到用户空间缓冲区,当用户空间缓冲区满或者写操作结束时,才将用户缓冲区的内容写到内核缓冲区,同样的道理,当内核缓冲区满或写结束时才将内核缓冲区内容写到文件对应的硬件媒介。
二、 库函数:
顾名思义是把函数放到库里,是把一些常用到的函数编完放到一个文件里,供别人用。别人用的时候把所在的文件名用#include<>加到里面就可以了,一般放到lib文件里。库函数一般分为两类:一种是C语言标准规定的库函数,一类是编译器特定的库函数。libc就是一个C标准库,里面放着一些基本的函数,这些函数都被标准化了。
库函数调用通常用于应用程序中对一般文件的访问,库函数调用是系统无关的,因此移植性好。
库函数主要由两方面提供:一是操作系统提供的;另一类是由第三方提供的。
系统提供的这些函数把系统调用进行封装或者组合,可以实现更多的功能,这样的库函数能够实现一些对于内核来说比较复杂的操作。比如read函数根据参数,直接就能读文件,而背后隐藏的文件比如在那个磁道,那个扇区,加载到那个内存,是程序员不必关心的问题。这些操作里面也包含了系统调用。
对于第三方库,其实和系统库一样,只是他直接利用系统调用的可能性要小一些,而是系统提供的API接口来是实现(API接口是开放的)。比如printf和getchar这样,他们都是一个“外壳”,真正实现的不是它们本身,而是调用了别的函数。
如printf的实现最终还是调用了putc()和user.h中的write()这样的系统调用,而另一些则不会使用系统调用,比如strlen,strcat,memcpy等;库函数大部分是对系统函数的封装(不绝对),这个世界上很少有绝对的事儿,例如世间一切的长度和质量等数字问题都不是绝对准确的,只是一个-----约等于。
事实上,系统调用所提供给用户的是直接而纯碎的高级服务,如果想要更加人性化,具有更符合特定情况的功能,那么就要我们用户自己定义,因此衍生了库函数,它把部分系统调用包装起来。比如当我们要用C语言打印一句话的时候,如果没有用到库函数printf,那么我们就需要自己实现就需要调用putc()和write()等这样一些系统函数。显得比较麻烦,所以系统调用是为了方便使用操作系统的接口,而库函数则是为了人们编程的方便。
库函数的调用是语言或者应用程序的一部分,而系统调用则是操作系统的一部分。
系统调用是应用程序与内核交互的接口。人们在长期的编程中发现使用系统函数有个重大的缺点,那就是程序的移植性。例如linux提供的系统调用的函数和windows就不一样。但是大部分的系统调用函数的速度库函数调用的速度要快。
库函数调用则是面向应用开发的,相当于应用程序的api,采用这样的方式有很多原因:
(1):双缓冲技术;
(2):移植性;
(3):底层调用本身存在的一些缺陷;
(4):让api也可以有了级别和专门的工作面向;
API(Application Programming Interface),win32API也就是MicrosoftWindows32位平台的应用程序编程接口。windows规定一切的应用程序优先级为3,为windows自己的为0(0最高,3最低)。windows不允许应用程序直接访问硬件,但是会提供API函数让用户间接地访问,这样就会调用系统级API。平时出现的“...非法操作”就是因为应用程序非法访问硬件造成的。
API分为两种:
第一:用户级API;替用户写好函数,方便调用,使程序员可以将焦点放在设计程序逻辑上面,而不必再编写繁琐、重复的程序,不必关注技术的细节。例如VC++,MFC,VB等都是类库和各种控件,它代替了API的神秘功能。
第二:系统级API;如果应用程序想要和硬件交互,必须调用此类函数。程序员调用的是API(api函数),然后通过与系统调用共同完成函数的功能。因此,API是一个提供给应用程序的接口,一组函数,是与程序猿直接进行交互的。系统调用则不与程序员进行交互,它是根据API函数,通过一个软件中断机制向内核提交请求(trap指令类似于一个系统中断,系统也会有一个特殊的中断处理函数(interrupt handler)来处理用户的请求),以获得内核服务的接口。并不是所有的API函数都一一对应一个系统的调用,有时,一个API函数会需要几个系统调用共同来完成函数的功能,甚至一些API函数不需要调用相应的系统调用,不需要内核提供的服务。
问题二:什么是回调函数?
回调函数就是一个通过函数指针调用的函数,使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。也就是把需要执行的代码地址给系统,系统在恰当的时候执行。这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。类似于中断处理机制,中断在某方面使计算机变得智能!
系统回调函数必须是由系统调用,但是这个函数可以是用户编写的,完成相应的功能服务。