库函数:
库函数是什么?在百度百科中这样解释到:库函数(Library function)是把函数放到库里,供别人使用的一种方式。.方法是把一些常用到的函数编完放到一个文件里,供不同的人进行调用。调用的时候把它所在的文件名用#include<>加到里面就可以了。一般是放到lib文件里的。简单来说,就是一些功能函数(例如strlen、memset...),当你想使用实现求得一个字符串的长度这样一个函数时,不用亲自实现,因为在string库里已经实现了,并把这个功能写成了strlen函数,所以程序员只用引进这个库(#include <string.h>),然后调用这个函数(strlen();)就好了。也就是说,库是一些特定功能的集合。
库函数分为两种:动态库、静态库。
静态库就是向上文所描述的那样,在编写源代码的时候引进,也就是说,在编译源代码时,连同静态库一起编译了。这样的结果就导致一个问题,当程序员只想使用库中的某一个函数时,他必须把整个库引进,这样编译过后没有问题,但是编译过后的程序显得比较笨重,因为C语言程序难免会嵌套包含众多头文件,编译大量的代码都是让电脑在做无用功,因为整个程序不会用到所有的函数!
所以就有了动态库,也叫做动态链接库和共享库。动态库是在程序编译完成之后的链接阶段链接到程序中,动态库的本质是一些已经编译过后的函数方法集合。在动态库中,所有的函数都已经被提前编译过,在一个工程中,动态库和其他代码在不同的文件中,在程序链接的过程中,已经实现符号决议、地址空间分配、符号的重定位。所以对程序来说,它需要用到哪个库函数,就链接哪个库函数,让程序不同的模块用不同的动态链接库是在工程中良好的习惯,不然当你每次需要更新发布的应用程序,就得整个程序重新编译一遍,这不仅对于服务器编程来说是致命的,对于应用程序来说也是一件想想就很可怕的事情。
补充:不同库在不同系统上的后缀。
windows linux
静态库 .lib .a
动态库 .dll .so
系统调用号:
操作系统对于每一个系统调用API都有一个long类型的编号来记录,这个编号就是系统调用号。
系统调用表:
而所有的系统调用号,就存放在系统调用表中,并且在该表中,每一个系统调用的下标就是系统调用号。
例如以上源码中的截取片段,就是系统调用表的一部分,其中sys_open这个系统调用的系统调用号就为5。
用户态与内核态:
现在我们来说说用户态和内核态。之前一直不理解老师口中所说的用户态与内核态的转换,为什么计算机执行到某局代码时会转到内核态?
通俗来说,在计算机运行某个程序时,用户态就是由用户来使用、管理并且有权限使用的部分,那内核态就是用户没办法使用或者说是没有权限使用的啦。这就是我之前粗略的理解,那为什么要这样设置呢?其实想一想也很简单,人们操作计算机,也只能从表面操作,而不能直接上手去读取磁盘、写入数据、打印输出,虽然我们下达了这些指令,但是真正执行这些指令的是操作系统。类比起来也很简单,就像我们去食堂买饭,我们在下达了要吃黄焖鸡的命令后,我们并不会真正亲自去做黄焖鸡,而是在窗口等着,然后食堂阿姨做好了,端给我们,结束这趟业务。
此时我们再看一看百度百科的定义:
这里的被中断程序中断就可以类比为在点黄焖鸡的过程中,食堂阿姨接收到命令,她转身去做黄焖鸡,而你就被阻塞住了,在窗口等待的过程。当然也可以不被阻塞,你可以选择去买杯水或者找个地方放个书包,这就是程序中的并发运行了,这里就不讨论了。
系统调用:
通过上文,终于可以知道简单的结论了:系统调用就是操作系统为程序员操作程序留下的接口,由操作系统定义并实现,是操作系统和 应用程序之间的连接桥梁。深入来说,就是程序发出系统调用的命令,然后
由内核来执行的一些方法。
最后配上一张当执行一下代码时的用户态和内核态转换的图。
1 void test() 2 { 3 ... 4 int fd = open(...); 5 ... 6 }