系统调用

  • 系统调用是受控的内核入口,借助于这一机制,进程可以请求内核以自己的名义去执行某些动作。
  • 以应用程序编程接口(API)的形式,内核提供有一系列服务供程序访问。
  • 关于系统调用需关注一下几点:

    • 系统调用将处理器从用户态切换到核心态,以便CPU访问受到保护的内核内存
    • 系统调用的组成是固定的,每个系统调用都由一个唯一的数字来标识
    • 每个系统调用可辅之以一套参数,对用户空间与内核空间之间传递的信息加以规范。
  • 从C语言编程的角度来看,调用C语言函数库的外壳函数等同于调用相应的系统调用服务例程。

库函数

  • 一个库函数是构成C语言函数库的众多库函数之一。
  • 许多库函数不会使用任何系统调用;另一方面,还有些库函数构建与系统调用层之上。
  • 往往,设计库函数是为了提供比底层系统调用更为方便的调用接口。

标准C语言函数库;GNU C语言函数库(glibc

标准C语言函数库的实现随UNIX的实现而异。GNU C语言函数库是Linux上最常用的实现。

确定系统的glibc版本

shell中可直接运行glibc共享库文件————将其视为可执行文件,来获取glibc版本

$ /lib/libc.so.6

而要确定该库的位置:可以针对某个与glibc动态链接的可执行文件运行ldd程序。

处理来自系统调用和库函数的错误

几乎每个系统调用和库函数都会返回某类状态值,用以表明调用成功与否。要了解调用是否成功,必须坚持对状态值进行检查。若调用失败必须采取相应行动,至少应该显示错误消息。

少数几个系统调用在调用时从不失败。例如,gitpid()总能成功返回进程ID,而_exit()总能终止进程。无需对此类系统调用的返回值进行检查。

处理系统调用错误

  • 通常,返回值为 -1 表示出错;而且会将全局整型变量errno设置为一个正值,以标识具体错误。<errno.h>头文件提供了对errno的声明,以及一组针对各种错误编号而定义的常量。所有这些错误都以字母E打头。
  • 如果系统调用和库函数成功,errno绝不会被重置为0,故此,该变量不为0可能是之前调用失败造成的。因此,在进程错误检查时,必须坚持首先检查函数的返回值是否表明调用出错,然后再检查errno确定错误原因
  • 少数系统调用在调用成功后也会返回 -1。要判断此类系统调用是否出错,应在调用前将 errno 置为0,并在调用后对其检查
  • 系统调用失败后,常见的做法是根据errno打印错误消息。提供库函数perror()strerror()就是出于这一目的。

处理来自库函数的错误

不同的库函数在调用发生错误时,返回的数据类型和值也各不相同。从错误处理的角度来说,可将库函数划分为以下几类:

  • 某些库函数返回错误的方式与系统调用完全相同————返回值为 -1,伴之以errno号来表示具体错误
  • 某些库函数在出错时会返回 -1 之外的其他值,但仍会设置errno来表明具体的出错情况
  • 还有些函数根本不使用errno

总结

本章重点介绍了系统调用和库函数,并说明其关系;然后说明了函数库所需的动态库文件;最后介绍了错误处理。

标签: Linux, C/C++, TLPI

添加新评论