函数库调用 VS 系统调用
函数库调用
|
系统调用
|
在所有的ANSI C编译器版本中,C库函数是相同的 | 各个操作系统的系统调用是不同的 |
它调用函数库中的一段程序(或函数) | 它调用系统内核的服务 |
与用户程序相联系 | 是操作系统的一个入口点 |
在用户地址空间执行 | 在内核地址空间执行 |
它的运行时间属于“用户时间” | 它的运行时间属于“系统”时间 |
属于过程调用,调用开销较小 | 需要在用户空间和内核上下文环境间切换,开销较大 |
在C函数库libc中有大约300个函数 | 在UNIX中大约有90个系统调用 |
典型的C函数库调用:system fprintf malloc | 典型的系统调用:chdir fork write brk; |
从程序完成的功能来看,函数库提供的函数通常是不需要操作系统的服务,函数是在用户空间内执行的,除非函数涉及到I/O操作等,一般是不会切到核心态的。系统调用是要求操作系统为用户提供进程,提供某种服务,通常是涉及系统的硬件资源和一些敏感的软件资源等。
函数库的函数,尤其与输入输出相关的函数,大多必须通过Linux的系统调用来完成。因此我们可以将函数库的函数当成应用程序设计人员与系统调用程序之间的一个中间层,通过这个中间层,我们可以用一致的接口来安全的调用系统调用。这样程序员可以只要写一次代码就能够在不同版本的linux系统间使用积压种具体实现完全不同的系统调用。至于如何实现对不同的系统调用的兼容性问题,那是函数库开发者所关心的问题。
从程序执行效率来看,系统调用的执行效率大多要比函数高,尤其是处理输入输出的函数。当处理的数据量比较小时,函数库的函数执行效率可能比较好,因为函数库的作法是将要处理的数据先存入缓冲区内,等到缓冲区装满了,再将数据一次写入或者读出。这种方式处理小量数据时效率比较高,但是在进行系统调用时,因为用户进程从用户模式进入系统核心模式,中间涉及了许多额外的任务的切换工作,这些操作称为上下文切换,此类的额外工作会影响系统的执行效率。但是当要处理的数据量比较大时,例如当输入输出的数据量超过文件系统定义的尽寸时,利用系统调用可获得较高的效率。
总结:
系统调用:是属于内核、面向硬件设备的一类接口,在内核中执行,调用时消耗较大。各个系统的系统调用(列: windows和Linux)是不同的。
标准C库:即ANSI C,在用户层,已标准化了的统一的接口(API);也就是说:各个操作系统的标准C库的接口是一样 的,但是由于每个操作系统的系统调用不同,所以,他在各个操作系统的实现是不一样的。只是接口是一 样的。这也是我们使用标准C库,所写的程序具有很好的移植性的原因,它只关心接口,不关心实现。
这也是Linux下的C库与windows的C库是不能相互的替换的原因,
C库:可分为两类,一类是:标准C库,由系统提供,把系统调用封装或是组合。
二类是:是第三方提供:列:我们基于系统调用开发的库。
Linux C中库函数和系统调用的区别
库函数是高层的,完全运行在用户空间,为程序员提供调用真正的在幕后完成实际事务的系统调用的更方便的接口。系统调用在内核态运行并且由内核自己提供。标准C库函数printf()可以被看做是一个通用的输出语句,但它实际做的是将数据转化为符合格式的字符串并且调用系统调用 write()输出这些字符串。
是否想看一看printf()究竟使用了哪些系统调用? 这很容易,编译下面的代码。
复制代码 代码如下:
#include <stdio.h>
int main(void)
{ printf("hello"); return 0; }
使用命令gcc -Wall -o hello hello.c编译。用命令 strace hello 跟踪该可执行文件。是否很惊讶? 每一行都和一个系统调用相对应。 strace是一个非常有用的程序,它可以告诉你程序使用了哪些系统调用和这些系统调用的参数,返回值。 这是一个极有价值的查看程序在干什么的工具。在输出的末尾,你应该看到这样类似的一行 write(1, "hello", 5hello)。这就是我们要找的。藏在面具printf() 的真实面目。既然绝大多数人使用库函数来对文件I/O进行操作(像 fopen, fputs, fclose)。 你可以查看man说明的第二部分使用命令man 2 write 。man说明的第二部分专门介绍系统调用(像kill()和read())。 man说明的第三部分则专门介绍你可能更熟悉的库函数(像cosh()和random())。
你甚至可以编写代码去覆盖系统调用,正如我们不久要做的。黑客常
这样做来为系统安装后门或木马。 但你可以用它来完成一些更有益的事,像让内核在每次某人删除文件时输出 “ Tee hee, that tickles!” 的信息
(具体怎么实现?)