系统调用与库函数关系|学习笔记

简介: 快速学习系统调用与库函数关系

开发者学堂课程【物联网开发- Linux 高级程序设计全套视频系统调用与库函数关系】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/660/detail/10980


系统调用与库函数关系

 

内容简介:

一、库函数的函数类型

二、系统调用与库函数的关系

三、Printf函数执行过程

四、小结

 

一、库函数的函数类型

1、无需系统调用的

接下来讲系统调用和库函数的关系,首先讲一下库函数,库函数是由两类函数构成的:一类库函数不需要系统调用、另一类库函数需要系统调用,先看第一类库函数,它不需要切换到内核空间即可完成函数的全部功能,并且将结果返回给应用程序,比如 strcpy 、 bzero这些函数,例

如 strcpy 代码如下:

char * strcpy(char *dest,const char *src)

{

char *p=dest;

while(*src != ‘\0’)

{

*dest = *src;

src++;

dest ++;

}

*dest = ‘\0’;

return p;

}

看整个 strcpy 函数它是否系统调用内核函数?

没有,在应用程序这一层就已经把它的功能实现了,这就是 strcpy 的源码,这类函数是不需要系统调用的。

2、需要系统调用

但是有一类函数需要系统调用,需要切换到内核空间,这类函数通常通过封装系统调用去实现相应功能,比如 printf 或者 fread ,注意在 C 语言当中,库函数讲 fread 时,在 fread 函数的源码中,它肯定要去调 read ,它在去调 read 时通过 read 进入内核,因为read 函数是系统调用,应用程序只能通过系统调用进入内核,所以像 fread 的函数,它就需要系统调用,这是第二类库函数需要调系统调用的。

 

二、系统调用与库函数的关系

1、关系图展示

接下来看一张图,即库函数和系统调用的关系,并不是所有的系统调用都被封装成了库函数,系统提供的很多功能都必须通过系统调用才能实现,

看图如下所示:

image.gif

2、关系图解析

平常点击应用程序,在应用程序当中经常是调库函数,而库函数是分为两类,即需要系统调用的和不需要系统调用的,像 strcpy ,应用程序调 strcpy 是直接在 C 库里面建了;

还有一类在应用程序当中,比如 fread , fread 去调库函数,再去调 read 、调系统调用,然后通过系统调用接口,进入内核,通过内核再去往硬盘上的文件中写入数据,它是一个过程;

还有一种是在应用程序当中可以直接系统调用,调 read 直接将数据写到文件里面去。

在此要注意, read 可以调 fread ,即间接的调 read ,像有些函数即创建多进程的函数就不在库函数当中,它就只能通过系统调用进入内核,在内核当中创建多任务,这就是库函数跟系统调用的关系,库函数有的不需要系统调用,有的需要系统调用,像 strcpy 是在用户态就可以实现功能,像fread 必须要用户态切到内核态才能实现功能。

3、频繁系统调用的影响

系统调用是需要时间的,程序当中频繁地使用系统调用会降低程序的运行效率,这是什么意思?

正常情况下应用程序是运行用户态,如果系统调用它是要切换到内核态的,注意如果切换到内核态,它要保存用户态的环境,然后调完了之后又返回到系统调用函数,然后再返回到用户态时再恢复环境,所以由用户态切换到内核态,且系统调用调完了之后、运行完内核函数之后,再返回到用户态时,其中状态的切换是需要消耗资源的,即保存环境恢复环境,所以如果频繁的进出内核,就会降低程序的运行效率。

4、用户态和内核态的区分原因

为什么分用户态和内核态?是为了保护操作系统内核,在电脑或手机上运行一个程序之后,经常那个应用程序会死机,但它并不会导致手机或电脑重启,操作系统不会崩掉,应用程序崩了就将应用程序杀死,然后操作系统不会崩,这样它便将程序运行状态分为用户态和内核态,正常情况下是不允许进入内核态的,除非通过系统调用进去,这样就有力地保护了内核,使操作系统更加稳定,然后注意频繁进出内核会降低程序的运行效率,因为会有环境的切换。

5、缓冲区的概念

在讲 fread 、 printf 、 C 语言时讲过缓冲区的概念,其实缓冲区相当于一块内存,像在程序的内存当中有一个数组 str ,要想把它写到文件里面打到屏幕上,首先库函数会将此数据先放到缓冲区里,最终它会刷到文件里边,即普通文件或者设备软件里面去,那么为什么要有缓冲区?是为了减少进出内核的次数,先将东西积累在缓冲区里边,然后积累到一定程度之后或当满足某种条件的时候,进出内核一次就可以搞定,相当于给你一个苹果,你跑一趟办公室,再给你一个苹果,你再跑一趟办公室,这样是没有效率的,给你一个苹果,你放到篮子里,给一个苹果就放在篮子里,当满足某种条件时,你提着篮子将许多个苹果一次送到办公室,这种效率会高一些,

请参考下图:

image.gif

 

三、printf 函数执行过程

在 printf 函数执行的过程,在应用程序当中去调 printf ,那么 C库当中它会将数据写到缓冲区里,最终它会调 write ,然后调系统调用,将缓冲区里的数据写到文件里面去,即标准输出设备文件里面,然后便到了屏幕上,这是一个程序执行的过程,

如下图所示:

image.gif

 

四、小结

上述的第一张图中清晰的讲了库函数跟系统调用内核函数之间的关系、用户态和内核态的两种状态、保护内核态用的频繁切换会降低程序运行效率,所以说就有缓冲区的概念,这是系统调用和库函数,库函是 C 库提供的,系统调用是内核提供,系统调用就是是内核提供的接口函数,在整个系统编程阶段就学各种各样的系统调用,学各种各样的内核提供的函数,能看明白和会调用,便能够实现相应的功能。

 

相关文章
|
3天前
|
存储 Linux 编译器
再论系统调用
再论系统调用
31 0
|
3天前
|
存储 缓存 Unix
C语言第四章(进程间的通信,管道通信,pipe()函数)
C语言第四章(进程间的通信,管道通信,pipe()函数)
77 0
|
3天前
|
存储 Unix C语言
C语言进程(第三章,exec函数族,execl,execlp,execle,execv,execvp,execve)
C语言进程(第三章,exec函数族,execl,execlp,execle,execv,execvp,execve)
35 0
|
3天前
|
安全 Java 程序员
“系统调用”究竟是不是个函数?
- **系统调用**和普通**函数**有何区别? - 什么是**内核态** 和 **用户态**? - 操作系统如何让CPU切换状态? - 内中断、外中断、软中断、硬中断是什么意思? - 库函数和系统调
|
7月前
|
存储 监控 Linux
《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数
《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数
97 0
|
9月前
|
Serverless C语言
C语言——利用函数实现某一特定功能
C语言——利用函数实现某一特定功能
231 0
|
11月前
|
安全
驱动开发:取进程模块的函数地址
在笔者上一篇文章`《驱动开发:内核取应用层模块基地址》`中简单为大家介绍了如何通过遍历`PLIST_ENTRY32`链表的方式获取到`32位`应用程序中特定模块的基地址,由于是入门系列所以并没有封装实现太过于通用的获取函数,本章将继续延申这个话题,并依次实现通用版`GetUserModuleBaseAddress()`取远程进程中指定模块的基址和`GetModuleExportAddress()`取远程进程中特定模块中的函数地址,此类功能也是各类安全工具中常用的代码片段。
186 0
|
11月前
|
存储 API Windows
驱动开发:内核中进程与句柄互转
在内核开发中,经常需要进行进程和句柄之间的互相转换。进程通常由一个唯一的进程标识符(PID)来标识,而句柄是指对内核对象的引用。在Windows内核中,`EProcess`结构表示一个进程,而HANDLE是一个句柄。为了实现进程与句柄之间的转换,我们需要使用一些内核函数。对于进程PID和句柄的互相转换,可以使用函数如`OpenProcess`和`GetProcessId`。OpenProcess函数接受一个PID作为参数,并返回一个句柄。GetProcessId函数接受一个句柄作为参数,并返回该进程的PID。
327 0
|
Linux C语言
Linux系统调用一、系统调用与C库函数的关系 —— 从进程虚拟地址空间和文件描述符的角度分析
Linux系统调用一、系统调用与C库函数的关系 —— 从进程虚拟地址空间和文件描述符的角度分析
171 0
Linux系统调用一、系统调用与C库函数的关系 —— 从进程虚拟地址空间和文件描述符的角度分析
|
缓存 Linux API
系统编程之文件IO(七)——0,1,2三个文件描述符与库函数和系统调用的区别
系统编程之文件IO(七)——0,1,2三个文件描述符与库函数和系统调用的区别
系统编程之文件IO(七)——0,1,2三个文件描述符与库函数和系统调用的区别