不同于Java的异常处理机制, 当你使用C更多的接触到是基于错误码的异常机制, 简单来说就是当调用的函数发生异常时, 程序不会跳转到一个统一处理异常的地方, 取而代之的是返回一个整型错误码。

可能会有小伙伴有疑问了, 以打开文件为例该函数定义如下所示

int open(const char *pathname, int flags);

如果打开文件成功, open函数会返回一个文件描述符(该值大于0), 如果失败则返回-1。对于开发者来说, 只知道文件打开失败了, 而却不知道具体原因, 实际上的原因可能是多种多样的, 如:

  • 文件不存在
  • 当前进程没有该文件的读写权限

那么该如何知道具体错误呢? 这就需要借助系统为我们提供的errno机制了。

errno

errno是一个定义在errno.h头文件的全局整型变量,表示当前发生的最后一个错误, 只需在代码中引用errno.h这个头文件边可以获取到这个值。

如以下demo所示, 我们尝试打开一个不存在的文件

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h> int main() {
int fd;
fd = open("/test.log", O_RDONLY);
if (fd == -1) {
printf("open failed, errno: %d\n", errno);
}
return 0;
}

运行该程序, 输出如下所示:

open failed, errno: 2

可以看出,此时错误码为2, 怎么知道这个错误码代表什么意思呢?

有以下方式

moreutils

  1. 安装moreutils
apt install moreutils
  1. 运行errno 错误码查看具体的错误信息

可以验证, 错误码2表示当前文件或目录不存在,与我们的预期一致

perror

使用定义在stdio.h中的perror函数可以直接在标准输出上打印错误信息

该函数定义如下所示, 我们可以在错误信息前附加自己定义的错误信息。

void perror(const char *s);

Demo:

int main() {
int fd;
fd = open("/test.log", O_RDONLY);
if (fd == -1) {
perror("open failed");
}
return 0;
}

输出:

strerr

如果我们只需要获取错误码对应的文本以记录日志, 可以使用strerr函数, 该函数定义在string.h

Demo:

int main() {
int fd;
fd = open("/test.log", O_RDONLY);
if (fd == -1) {
char* err_msg = strerror(errno);
printf("%s\n", err_msg);
}
return 0;
}

输出

线程安全的吗?

相信对于并发问题比较敏感的同学已经意识到了一个问题:这errno是一个整型的全局变量, 那如果多个线程同时执行系统调用, 并且都因为不同的原因失败了, 会不会导致其他线程的错误信息全部被最后一个产生错误的线程给覆盖掉了? 以及会不会有线程安全问题呢?

实际上errno被定义为了线程局部变量, 概念同Java中的ThreadLocal, 即每个线程都会有自己的errno变量, 不同线程之间不会互相影响。

写给初学者的Linux errno 错误码机制的更多相关文章

  1. linux的错误码error

    在程序出错时,我们通过全局变量错误号errno和perror函数能够很快的定位到错误原因. Linux错误代码及其含义 C Name Value Description 含义Success 0 Suc ...

  2. errno 错误码

    转自:http://baike.baidu.com/link?url=uX-q7K-TTL-5AFNT-hjhAP6fvgAwvsNkIMqJqJ3GEspYgtQXsovEEzpqmQ3ZmAgql ...

  3. Linux的错误码

    在使用时需要包含头文件 #include <errno.h> merlin@tfAnalysis:~/projects/tfradius$ cat /usr/include/asm-gen ...

  4. errno错误码及含义(中文)

    /usr/include/asm/errno.h #define EPERM 1 /* Operation not permitted */操作不允许 #define ENOENT 2 /* No s ...

  5. 写给初学者的话---linux使用说明

    2018年noip上海赛区可以使用window操作系统的美梦终究还是破灭了!!!!上海大部分noip选手都陆陆续续开始改linux........好吧,那我们今天来看看linux操作系统中,noip选 ...

  6. Linux 内核错误码

    #define    EPERM         1    /* Operation not permitted */#define    ENOENT        2    /* No such ...

  7. Linux环境下错误码及意义总结

    Linux的错误码包含在/usr/include/asm-generic/errno-base.h和/usr/include/asm-generic/errno.h 这两个文件内: #ifndef _ ...

  8. .NET中异常与错误码优劣势对比

    .NET之所以选择异常,而不是返回错误码来报告异常,是由于前者有以下几个优势: 1.异常与oop语言的结合性更好.oop语言经常需要对成员签名强加限制,比如c#中的构造函数.操作符重载和属性,开发者对 ...

  9. errno.h 错误码描述.

    描述:一般说的Linux源码的目录,默认是基于 /usr/include/ 的. 使用 char *strerror(int errnum); 函数打印错误代码的描述.我简单对比了一下,发现描述大体一 ...

随机推荐

  1. 不关闭selinux下配置php+httpd访问KingbaseES

    在不关闭selinux的情况下使httpd+php+KingbaseES正常使用1.正常设置php.apache 除了正常流程外还需要在/etc/sysconfig/httpd最后追加LD_LIBRA ...

  2. 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 百篇博客分析OpenHarmony源码 | v37.03

    百篇博客系列篇.本篇为: v37.xx 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...

  3. 鸿蒙源码分析系列(总目录) | 百万汉字注解 百篇博客分析 | 深入挖透OpenHarmony源码 | v8.23

    百篇博客系列篇.本篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析 | 51.c.h .o 百篇博客.往期回顾 在给OpenHarmony内核源码加注过程中,整理出以下 ...

  4. P7599-[APIO2021]雨林跳跃【二分,倍增,ST表】

    正题 题目链接:https://www.luogu.com.cn/problem/P7599 题目大意 \(n\)棵树,在某棵树上时可以选择向左右两边第一棵比它高的树跳,现在\(q\)次询问从\([A ...

  5. P4199-万径人踪灭【FFT】

    正题 题目链接:https://www.luogu.com.cn/problem/P4199 题目大意 给出一个只包含\(a,b\)的字符串 求有多少个不连续的回文子序列(字母回文,位置对称) \(1 ...

  6. WPF进阶技巧和实战06-控件模板

    逻辑树和可视化树 System.Windows.LogicalTreeHelper System.Windows.Media.VisualTreeHelper 逻辑树类(LogicalTreeHelp ...

  7. apiserver源码分析——启动流程

    前言 apiserver是k8s控制面的一个组件,在众多组件中唯一一个对接etcd,对外暴露http服务的形式为k8s中各种资源提供增删改查等服务.它是RESTful风格,每个资源的URI都会形如 / ...

  8. Java-爬虫-小项目

    爬取数据:(获取请求返回的页面信息,筛选出我们想要的数据就可以了!) 项目地址:https://gitee.com/zwtgit/java-reptile 导入依赖,写一个工具类 <depend ...

  9. 『基于ArcGIS的Python编程秘籍(第2版)』书本源码

    ArcPy学习 第1章 面向ArcGIS的Python编程语言的基础 略 第2章 管理地图文档和图层 引用当前的地图文档 引用磁盘上的地图文档 获取地图文档的图层列表 限制图层列表 缩放至所选要素 改 ...

  10. vue 动态菜单以及动态路由加载、刷新采的坑

    需求: 从接口动态获取子菜单数据 动态加载 要求只有展开才加载子菜单数据 支持刷新,页面显示正常 思路: 一开始比较乱,思路很多.想了很多 首先路由和菜单共用一个全局route, 数据的传递也是通过s ...