上周总结了《C 标准库的基础 IO》,其实这些功能函数通过「系统调用」也能实现相应功能。这次文章并不是要详细介绍各系统调用接口的使用方法,而是要深入理解「库函数」与「系统」调用之间的关系和区别。

一、系统调用

系统调用,我们可以理解是操作系统为用户提供的一系列操作的接口(API),这些接口提供了对系统硬件设备功能的操作。这么说可能会比较抽象,举个例子,我们最熟悉的 hello world 程序会在屏幕上打印出信息。程序中调用了 printf() 函数,而库函数 printf 本质上是调用了系统调用 write() 函数,实现了终端信息的打印功能。

二、库函数

库函数可以理解为是对系统调用的一层封装。系统调用作为内核提供给用户程序的接口,它的执行效率是比较高效而精简的,但有时我们需要对获取的信息进行更复杂的处理,或更人性化的需要,我们把这些处理过程封装成一个函数再提供给程序员,更方便于程序猿编码。

库函数有可能包含有一个系统调用,有可能有好几个系统调用,当然也有可能没有系统调用,比如有些操作不需要涉及内核的功能。可以参考下图来理解库函数与系统调用的关系。

三、系统调用意义

  • 避免了用户直接对底层硬件进行编程。比如最简单的hello world程序是将信息打印到终端,终端对系统来说是硬件资源,如果没有系统调用,用户程序需要自己编写终端设备的驱动,以及控制终端如何显示的代码。
  • 隐藏背后的技术细节。比如读写文件,如果使用了系统调用,用户程序无须关心数据在磁盘的哪个磁道和扇区,以及数据要加载到内存什么位置。
  • 保证系统的安全性和稳定性。要知道用户程序是不能直接操作内核地址空间的,比如一个刚出道的程序猿,让他直接去访问内核底层的数据,那么内核系统的安全性就无法保证。而系统调用的功能是由内核来实现,用户只需要调用接口,无需关心细节,也避免了系统的安全隐患。
  • 方便程序的移植性。如果针对一个系统资源的功能操作比如 write(),大家都按照自己思路去实现这个功能,那么我们写出来的程序的移植性就会非常差。

总而言之,我们只需要把系统调用当作一个接口,而这个接口能实现我们的一个功能,既方便又安全。

四、库函数 vs 系统调用

参考了《C 专家编程》书籍中的附录 A.4,书中关于两者区别的回答是这样的,函数库调用是语言或应用程序的一部分,而系统调用是操作系统的一部分。

  • 所有 C 函数库是相同的,而各个操作系统的系统调用是不同的。
  • 函数库调用是调用函数库中的一个程序,而系统调用是调用系统内核的服务。
  • 函数库调用是与用户程序相联系,而系统调用是操作系统的一个进入点
  • 函数库调用是在用户地址空间执行,而系统调用是在内核地址空间执行
  • 函数库调用的运行时间属于「用户」时间,而系统调用的运行时间属于「系统」时间
  • 函数库调用属于过程调用,开销较小,而系统调用需要切换到内核上下文环境然后切换回来,开销较大
  • 在C函数库libc中大约 300 个程序,在 UNIX 中大约有 90 个系统调用
  • 函数库典型的 C 函数:system, fprintf, malloc,而典型的系统调用:chdir, fork, write, brk

据书中记载,库函数调用大概花费时间为半微妙,而系统调用所需要的时间大约是库函数调用的 70 倍(35微秒),因为系统调用会有内核上下文切换的开销。纯粹从性能上考虑,你应该尽可能地减少系统调用的数量,但是,你必须记住许多 C 函数库中的程序通过系统调用来实现功能。

五、正确理解库函数高效于系统调用

首先解释,上述说明的库函数性能远高于系统调用的前提是,库函数种没有使用系统调用。再来解释下某些包含系统调用的库函数,然而其性能确实也要高于系统调用。比如上篇文章中关于文件 IO 函数 fread、fwrite、fputc、fgetc 等,这些函数通常情况下性能确实比系统调用高,原因在于这些库函数使用了缓冲区,减少了系统调用的次数,因而显得性能比较高。

六、系统调用是如何运行的

上述内容基本说清楚了库函数与系统调用的概念以及它们之间的关系,下面我们来理解系统调用到底是如何运行的。

当一个进程正在运行,遇到读写文件操作,会发生一个中断,中断后系统会把当前用户进程的一些寄存器信息保存在内核堆栈中,接着去处理中断服务程序,这里是要去执行系统调用,Linux 中通过执行 int $0x80 来执行系统调用的中断,但内核实现了很多系统调用,这时需要传递「系统调用号」来指明需要哪个系统调用。

为了更清楚的说明系统调用的过程,我们这里参考网上的一段代码来实现系统调用:

int main()
{time_t tt; struct tm *t; asm volatile ("mov $0,%%ebx\n\t""mov $0xd,%%eax\n\t""int $0x80\n\t""mov %%eax,%0\n\t": "=m" (tt));  t = localtime(&tt);printf("Time: %d-%02d-%02d %02d:%02d:%02d\n",t->tm_year + 1900,t->tm_mon + 1, t->tm_mday,t->tm_hour, t->tm_min, t->tm_sec);
}[linuxblogs@host ~]$ gcc a.c -oa && ./a
Time: 2018-05-06 03:23:46

首先通过 mov $0xd %%eax 来将系统调用放入 %eax 寄存器中,time() 的系统调用号是 13,然后执行 int $0x80 系统就会去执行 time() 这个系统调用了。其实代码中的汇编部分就是实现 time() 系统调用的功能,汇编代码不懂没关系(我也不太懂),这里主要是为了说清楚系统调用的整个过程。

==================================================================================================

问:fopen open sys_open 内核函数 系统调用区别?

答:

系统调用是有一个 CPU 运行等级的提升问题. 用户代码在 3 级, 操作系统代码在 0 级.
open 是在 Ring 3 级对系统调用的一个包装. 
所有的系统函数只有一个系统调用入口, int $0x80, 在这条指令之前把调用的函数对应的功能号放到 %eax 寄存器.
这条指令产生一个中断, CPU 切换到中断处理程序, 运行等级从 Ring 3 级切换到 Ring 0 级. 开始在内核中运行. 内核再根据 %eax 中的功能号来调用不同的函数. sys_open 就是内核中处理 open 对应的功能号的函数.

操作系统提供的原型都是 C 接口的, 其它语言要用再进行包装就是.

转载:https://www.cnblogs.com/liwei0526vip/p/8998751.html

Linux 库函数与系统调用的关系与区别相关推荐

  1. Linux和Unix系统的关系和区别详细介绍

    1.简介 UNIX是一个功能强大.性能全面的多用户.多任务操作系统,可以应用从巨型计算机到普通PC机等多种不同的平台上,是应用面最广.影响力最大的操作系统. Linux是一种外观和性能与UNIX相同或 ...

  2. Linux 编程中的API函数和系统调用的关系【转】

    转自:http://blog.chinaunix.net/uid-25968088-id-3426027.html 原文地址:Linux 编程中的API函数和系统调用的关系 作者:up哥小号 API: ...

  3. 标准库函数和系统调用的区别

    写在前面:所谓标准库函数,这里暂时讨论C语言的标准库函数.库函数是语言本身的一部分,而系统函数是内核提供给应用程序的接口,属于系统的一部分.函数库调用是语言或应用程序的一部分,而系统调用是操作系统的一 ...

  4. Linux和UNIX的关系及区别

    (转载自http://c.biancheng.net/view/707.html) UNIX 与 Linux 之间的关系是一个很有意思的话题.在目前主流的服务器端操作系统中,UNIX 诞生于 20 世 ...

  5. Linux和UNIX的关系及区别(详解版)

    UNIX 与 Linux 之间的关系是一个很有意思的话题.在目前主流的服务器端操作系统中,UNIX 诞生于 20 世纪 60 年代末,Windows 诞生于 20 世纪 80 年代中期,Linux 诞 ...

  6. ie传递给系统调用的数据区域太小_【Linux系列】系统调用

    在现代OS中,内核提供了用户进程与内核进行交互的一组接口.这些接口让应用程序受限地访问硬件设备,提供了创建新进程并与已有进程进行通信的机制,也提供了申请OS其他资源的能力. 系统调用在用户空间进程和硬 ...

  7. fsync与fflush的关系和区别

    read/write/fsync与fread/fwrite/fflush的关系和区别 read/write/fsync: linux底层操作: 内核调用, 涉及到进程上下文的切换,即用户态到核心态的转 ...

  8. Java 内存 关系_JVM和Linux之间的详细内存关系

    JVM和Linux之间的详细内存关系 在一些具有8g物理内存的服务器上,主要运行Java服务.系统内存分配如下:Java服务的JVM堆大小设置为6g,监视过程大约需要600m,Linux本身使用大约8 ...

  9. Linux中brk()系统调用,sbrk(),mmap(),malloc(),calloc()的异同【转】

    转自:http://blog.csdn.net/kobbee9/article/details/7397010 brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的: ...

最新文章

  1. VC实现基于Office 2007 MODI 12.0实现图形文字识别(OCR)的程序
  2. qq应用之超级店长数据分析
  3. AI基础:经典卷积神经网络
  4. redis设置数据库数量databases
  5. 多目标遗传优化算法nsga2求解复杂约束问题【python源码实现,实数编码】
  6. PsTools在***中的一点小应用
  7. 前端跨域请求get_(单点登录)跨域SSO看这篇文章就够了:前端篇
  8. 交错排列(Alternating Permutation)问题详解
  9. 腾达AC15改内存闪存刷AC68U梅林
  10. EtherCAT报文格式详解
  11. Docker环境安装
  12. Java之自定义异常类、常用类String、StringBuilder、StringBuffer、时间类和枚举类的学习
  13. 抖音 iOS 工程架构演进
  14. 【剑指offer】一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
  15. springboot+网络空间安全实验教学中心门户网站 毕业设计-附源码191220
  16. 固定资产盘点的常用方法有哪些?
  17. chi2inv函数 matlab_matlab函数与指令大全 a——h (转载)
  18. 高仿360云盘android端的ui实现,(原创)高仿360云盘android端的UI实现
  19. 萨尔州大学计算机专业,萨尔大学介绍_QS世界排名_申请条件_优势专业-澳际留学网...
  20. java 获取Authorization信息

热门文章

  1. 1.什么是数据化运营——《数据挖掘与数据化运营实战》
  2. fastRPC的数据库服务
  3. krpano·分组图片地图插件
  4. 一个项目学会前端实现登录拦截
  5. Angular.js
  6. asm.js的陷阱1
  7. 修改XtraMessageBox的内容字体大小
  8. javascript---》arguments对象
  9. 中小企业 软交换机 呼叫中心 需要的请留言
  10. UA MATH567 高维统计IV Lipschitz组合2 Spherical Distribution的Lipschitz函数 Isoperimetric不等式