Linux——系统调用和库函数的区别

区别

  • 系统调用的实现在内核中,属于内核空间,系统调用的实现是在操作系统中,在编译操作系统的时候,就实现了该方法,所以用户是不可能去执行操作系统的代码,因此它的调用执行和库函数的调用执行是不一样的。

  • 库函数的实现在函数库中,属于用户空间,静态库,共享库,其实和我们自己在代码中实现一个方法去调用它,本质上没有什么区别,方法的实现均由用户自己完成。

上一篇博客中,我们也提到使用帮助手册查看的时候,不同的代号代表不同的含义
比如:fopen是库函数,而open是系统调用
在这里插入图片描述
在这里插入图片描述
凡是要对硬件或者操作系统底层做操作的话,就是系统调用。
有些功能,用户自己无法完成,需要操作系统来完成(往磁盘写入数据,操作PCB等)。

以open()为例,系统调用的执行过程如下:
在这里插入图片描述
在内核空间,对系统实现的方法进行编号,这个号是绝对的,以上是从内核源码中摘抄出来的一部分。
在内核中,系统调用表由系统调用号和系统调用方法的入口地址组成

  1. 应用程序去执行open的时候,就会产生中断,当前的这个应用程序无法继续往下执行
  2. 内核要开始处理这个中断,open执行以后,会将这个open对应的系统调用号5写到寄存器Eax中
  3. 接下来应用程序产生中断,应用程序就被换下去了,并进行现场保护,把当前的应用程序在CPU中运行的各个寄存器上的信息存在内核栈上
  4. 内核上来执行,操作系统从Eax寄存器中把系统调用号5读出来,在系统调用表查,查出来是sys_open,然后找到它对应的实现方法,然后就去打开一个文件,在内核中会创建一些数据结构,来表征这个打开的文件,再把open的返回值,也就是文件描述符写入到Eax寄存器中,相当于把刚才引发的中断处理完成
  5. 恢复应用程序的执行,恢复以后,首先第一时间从Eax寄存器把结果3读出来,赋给fd,然后应用程序继续向下执行。

因此,系统调用虽然效率很高,执行完之后去内核空间执行,但是,如果说频繁进行切换,切换的开销就比较大。

这也就是为什么printf会存在缓冲区的原因了.
因为当用户往屏幕上输出信息时,最终调用的是write的系统调用,如果不添加缓冲区,执行一下printf,马上切换到内核态,执行一下write,把内容写到屏幕上,然后刚恢复到用户空间,可能马上又要执行printf,将数据往屏幕上写,又要产生中断,切换到内核态,执行write,把数据写到屏幕上,然后恢复到用户空间,让应用程序执行,频繁切换,效率变得, 因此我们就给printf一个缓冲区,当执行printf方法,把打印的信息写到缓冲区中,等缓冲区满了之后,再从用户空间切换到内核空间,把数据全部写到屏幕上,只是切换一次,效率大大提高,开销也变小很多。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值