在学习Linux系统调用的时候,看PPT上说系统调用和库函数调用是有区别的,然而我在写代码的过程中却感受不到区别,都是在一个.cpp源文件中的函数,都要引头文件,只不过系统调用的头文件与之前学习C/C++时候常用的头文件不一样。之前学习C语言时候,常用的头文件如<stdio.h>
、<stdlib.h>
等等。系统调用的头文件基本可以通过man
命令来查找,例如在终端输入man 2 open
,进入 Linux Programmer’s Manual,如下图。
可以看到open
系统调用需要的头文件有#include <sys/types.h>
、#include <sys/stat.h>
、#include <fcntl.h>
这三个头文件。系统调用与C库函数的调用都是以C函数的形式出现,单单从代码编写角度看,似乎真的没有区别。根据教科书式的回答,它们的区别主要如下:
系统调用
概念
计算机的各种硬件资源是有限的,为了更好的管理这些资源,用户进程是不允许直接操作的,所有对这些资源的访问都必须由操作系统控制。为此操作系统为用户态运行的进程与硬件设备之间进行交互提供了一组接口,这组接口就是所谓的系统调用。
系统调用实质上就是函数调用,只不过调用的是系统函数,处于内核态而已。 用户在调用系统调用时会向内核传递一个系统调用号,然后系统调用处理程序通过此号从系统调用表中找到相应的内核函数执行,最后返回。
系统调用指运行在用户空间的程序向操作系统内核请求需要更高权限运行的服务。它通过软中断向内核态发出一个明确的请求。系统调用实现了用户态进程和硬件设备之间的大部分接口。
库函数
库函数用于提供用户态服务。它可能调用封装了一个或几个不同的系统调用(printf调用write),也可能直接提供用户态服务(atoi不调用任何系统调用)。
常见系统调用
open
,close
,read
,write
,fork
,exit
,getpid
,opendir
,readdir
,chmod
等,一般需要包含unistd.h
,sys/types.h
等头文件。
常见的库函数
printf
,scanf
,fopen
,fclose
,fclose
,fgetc
,fgets
,fprintf
,fscanf
,fputc
,malloc
,calloc
,strcat
,strcmp
,strcpy
,strlen
等需要引用stdio.h
,string.h
等头文件。
区别
- 系统调用通常不可替换,普通的库函数调用由函数库或自己提供。
程序员完全可以自己定义一个函数来平替库函数。 - 系统调用通常提供最小的接口,库函数提供较复杂的功能
例如sbrk
系统调用分配一块空间给进程,而malloc则在用户层次对分配 的空间进行管理。 - 系统调用运行在内核空间,而库函数运行在用户空间
系统调用属于内核,而库函数不属于内核,因此,当用户态进程使用系统调用时,CPU需要切换到内核态,并执行内核函数。 - 系统调用都返回一个整数值,而库函数并不一定如此。
在内核中,通常返回正整数或0表示系统调用成功,而负数(如-1)表示出错。 - 库函数的可移植性比系统调用好
在所有的ANSI C编译器版本中,C库函数都是相同的。但是各个操作系统的系统调用是不同的。 - 系统调用运行时间属于系统时间,库函数运行时间属于用户时间
- 系统调用开销相对库函数更大
由于双缓冲的实现,在用户态和内核态,都应用了缓冲技术。用户进程调用系统调用需要在用户空间和内核空间上下文切换,开销较大。库函数还会对系统调用的性能进行优化。
参考博客:[1] https://blog.youkuaiyun.com/hyb612/article/details/80473439
[2] https://blog.youkuaiyun.com/qq_43646576/article/details/102841078