原文地址http://daileinote.com/computer/linux_sys/02
系统调用是内核提供给外部程序的接口,进程可以通过系统调用来一自己的名义来执行某些动作。在深入了解系统调用之前,先关注以下几点。
1.系统调用处理器会从用户态切换到核心态以便能访问到内存核心空间。
2.系统调用的组成是固定的,每个系统调用都有一个唯一的数字来标识,而程序只是通过名称来调用。
从编程角度来讲,它跟c语言函数的调用很像,但是系统调用会经历的步骤往往更多。
系统调用内部细节已超出了本文的范围,普通的linux编程只需要记住以下几点
1.普通的一次系统调用开销是一次普通c库函数调用的20倍以上,所以用c普通函数解决的绝不用系统调用。
2.系统调用内核还需验证系统调用参数,用户空间内存和内核控件内存的复制
3.系统调用后我们都必须检查下返回值以及全局变量errno来确定系统调用是否报错了。
4.在linux上如果想检查一个程序执行了哪些系统调用,可用strace命令。
系统调用错误处理
系统调用的手册里都有记录调用可能的返回值,并指出哪些返回值表示错误。通常返回值是-1表示出错。
系统调用失败时会将全局整形变量errno设置为一个正值来标识具体错误。头文件<errno.h>提供了对errno的声明以及一些跟错误码有关的常量定义。
系统调用和库函数调用成功errno不会被重置为0,因此我们不能直接来判断errno来确定错误,有可能是之前的函数失败造成的。因此在检查错误时,必须先判断返回值,如果出错再根据errno来确定具体错误。
少数系统调用(如getpriority())在调用成功后也会返回-1,要判断此类系统调用是否发生错误,应提前将errno置为0,然后调用后再对errno进行判断。
void perror(const char *msg);
此函数会打印出字符串msg紧跟与当前errno值对应的错误描述。
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
int fd = open("aaa", O_WRONLY);
if(fd == -1){
perror("open");
}
return -1;
}
//open: No such file or directory
char *strerror(int errnum);
该函数会根据errnum错误号返回错误描述字符串,由于返回的字符串是静态分配的,这就意味着后续调用strerror()可能会覆盖之前的字符串,所以如果该错误描述后续还要用到,建议复制一个副本。
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(){
int fd = open("aaa", O_WRONLY);
char *tmp = strerror(errno);
printf("errno:%d, %s\n", errno,tmp);
printf("errno:%d, %s\n", 3,strerror(3));
printf("errno:%d, %s\n", 4,strerror(4));
}
/*
errno:2, No such file or directory
errno:3, No such process
errno:4, Interrupted system call
errno:1111, Unknown error 1111
*/
注意由于perror和strerror函数跟本地环境有关,所以如果你的linux是中文版的,则输出的字符串也会变成中文。