【Linux内核】Linux的errno和ERR_PTR、PTR_ERR简介
文章目录
- 1. Linux的errno和指针
- 1.1. 整型和指针类型转换
- 2. C语言中整型数据的存储和数据类型转换原理
- 2.1. 负数的强制类型转换
- 2.2. 强制数据类型降级
- 3. 测试程序
- 3.1. ARM测试结果
- 3.2. ARM64测试结果
1. Linux的errno和指针
常见的Linux函数返回值类型包括整型和指针,内核中这两种返回值类型的函数会互相调用。Linux的errno
为整型,为了与errno
对应,Linux将指针分为3种:
- 空指针:NULL,地址为0
- 异常指针:地址空间的高4095字节。
0xfffff001 - 0xffffffff
(32位)和0xfffffffffffff001 - 0xffffffffffffffff
(64位) - 普通指针
errno
的最大值MAX_ERRNO
在err.h
定义,值为4095。关于变量转换类型后的值,可以使用测试程序来进行测试。
long | void *(arm) | unsigned long(arm) | void *(arm64) | unsigned long(arm64) |
---|---|---|---|---|
0 | (nil) | 0 | (nil) | 0 |
-1 | 0xffffffff | 0xFFFFFFFF | 0xffffffffffffffff | 0xFFFFFFFFFFFFFFFF |
-MAX_ERRNO | 0xfffff001 | 0xFFFFF001 | 0xfffffffffffff001 | 0xFFFFFFFFFFFFF001 |
为了处理两种数据类型的转换,内核提供了include/linux/err.h
。
1.1. 整型和指针类型转换
interface | input | output | function |
---|---|---|---|
IS_ERR_VALUE | any | bool | 强制转换为unsigned long后,判断是否大于(unsigned long)-MAX_ERRNO |
ERR_PTR | long | void * | errno转指针 |
PTR_ERR | pointer | long | 指针转errno |
IS_ERR | pointer | bool | 判断指针是否异常 |
IS_ERR_OR_NULL | pointer | bool | 判断指针是否异常或NULL |
ERR_CAST | pointer | void * | 将任意类型的指针转为void型指针 |
PTR_ERR_OR_ZERO | pointer | int | 如果是异常指针,返回指针对应的errno,否则返回0 |
2. C语言中整型数据的存储和数据类型转换原理
其实,在C语言中,数值是以补码的形式存储的,正数存储的内容就是其本身(原码),负数补码的计算方法如下:
- 取绝对值
- 取反码,也就是对每一位取反
- 对反码加1,得到补码
以char型为例,-1在内存中的表示计算方法如下:
关于为什么使用补码存储数据,可以参整数在内存中是如何存储的,为什么它堪称天才般的设计。
2.1. 负数的强制类型转换
做强制类型转换时,就是把内存中的数据(补码)看作要转换的类型。将-1
强制转换为unsigned char
型时,就可得到值为0xFF,以此类推,可知将-
转换为unsigned long
时,值为0xFFFFFFFF
(32位)或0xFFFFFFFFFFFFFFFF
(64位)。同样的道理-4095
转换为unsigned long
时,值为0xFFFFF001
(32位)或0xFFFFFFFFFFFFF001
(64位)。需要注意的是,类型转换是临时的,转换的结果也会保存到临时的内存空间,不会改变数据本来的类型或者值。
2.2. 强制数据类型降级
数据类型级别从高到低为:
unsigned long long
long long
unsigned long
long
unsigned int
int
unsigned short
short
unsigned char
char
从高级到低级转换时,超出数值位数的高位部分将被丢弃。另外,降级转换也是是临时的。
3. 测试程序
#include <stdio.h>
#include <string.h>#define MAX_ERRNO 4095union err_t {int i;long l;unsigned int ui;unsigned long ul;void *p;char ch[sizeof(unsigned long)];
};static void test(long val)
{union err_t err;memcpy(&err, &val, sizeof(val));printf("int: %d\n", err.i);printf("long: %ld\n", err.l);printf("unsigned int: %u, 0x%08X\n", err.ui, err.ui);printf("unsigned long: %lu, 0x%08lX\n", err.ul, err.ul);printf("void *: %p\n", err.p);
}int main(void)
{printf("\ntesting: 0\n");test(0);printf("\ntesting: -1\n");test(-1);printf("\ntesting: -MAX_ERRNO\n");test(-MAX_ERRNO);#if 0printf("\ntesting: -4096\n");test(-4096);
#endifreturn 0;
}
3.1. ARM测试结果
交叉编译后使用QEMU运行查看结果。
arm-linux-gnueabihf-gcc -static -o err_arm err.c
qemu-arm err_arm
testing: 0
int: 0
long: 0
unsigned int: 0, 0x00000000
unsigned long: 0, 0x00000000
void *: (nil)testing: -1
int: -1
long: -1
unsigned int: 4294967295, 0xFFFFFFFF
unsigned long: 4294967295, 0xFFFFFFFF
void *: 0xfffffffftesting: -MAX_ERRNO
int: -4095
long: -4095
unsigned int: 4294963201, 0xFFFFF001
unsigned long: 4294963201, 0xFFFFF001
void *: 0xfffff001
3.2. ARM64测试结果
交叉编译后使用QEMU运行查看结果。
aarch64-linux-gnu-gcc -static -o err_aarch64 err.c
qemu-aarch64 err_aarch64
testing: 0
int: 0
long: 0
unsigned int: 0, 0x00000000
unsigned long: 0, 0x00000000
void *: (nil)testing: -1
int: -1
long: -1
unsigned int: 4294967295, 0xFFFFFFFF
unsigned long: 18446744073709551615, 0xFFFFFFFFFFFFFFFF
void *: 0xfffffffffffffffftesting: -MAX_ERRNO
int: -4095
long: -4095
unsigned int: 4294963201, 0xFFFFF001
unsigned long: 18446744073709547521, 0xFFFFFFFFFFFFF001
void *: 0xfffffffffffff001
【Linux内核】Linux的errno和ERR_PTR、PTR_ERR简介相关推荐
- [linux内核][LINUX内核编程]学习笔记(一)
linux内核使用bitmap相关 1,声明一个bitmap数组,可以表示100个bit,数组名字是bitmap [cpp] view plaincopy DECLARE_BITMAP(bitmap ...
- linux 内核 linux kernel travel
linux 内核 kernel_核 travel_旅行 linux kernel travel linux 2.6 1 hellomod.c 001 // hello world driver for ...
- 复制linux内核,linux内核写时复制机制源代码解读
作者简介 写时复制技术(一下简称COW)是linux内核比较重要的一种机制,我们都知道:父进程fork子进程的时候,子进程会和父进程会以只读的方式共享所有私有的可写页,当有一方将要写的时候会发生COW ...
- 生效linux内核,Linux内核
内核 单内核体系设计.但充分借鉴了微内核设计体系的优点,为内核引入模块化机制. 内核组成部分: kernel:内核核心,一般为bzimage,通常在/boot目录下,名称为vmlinuz kernel ...
- 哪些系统使用了linux内核,Linux操作系统有哪些
Linux操作系统有哪些 导语:Linux操作系统诞生于1991 年的10月5 日.Linux存在着许多不同的Linux版本,但它们都使用了Linux内核.Linux可安装在各种计算机硬件设备中,比如 ...
- 嵌入式烧写Linux内核,嵌入式linux 内核和根文件系统烧写方式简介
总体来说,嵌入式Linux内核和根文件的引导与PC机差不多. 嵌入式linux内核和根文件系统可以存放在各种可能的存储设备中,一般情况下我们将内核和根文件系统直接烧入到Flash中(包括NOR和NAN ...
- gcc与linux内核,linux内核版本及其编译的gcc版本
以前不知道,现在用crosstool-ng编译了5.2.0版本的arm-linu-gcc,再编译之前的linux-3.15.4发现会提示 include/linux/compiler-gcc.h:10 ...
- 如果查看linux内核,linux怎么查看内核版本
有朋友在使用Linux的过程中要查看Linux的内核版本号,这要怎么看呢?也有朋友文要怎么查看linux系统版本信息呢?下面和小编一起了解一下吧. 一.查看linux内核版本号 1:登录linux,在 ...
- 学做Linux内核,Linux内核学习(3) 最小系统制做2 busybox制做initrd.img和根文件系统...
busybox制做initrd.img和根文件系统 (一)开发环境介绍 1.使用win7_64的笔记本安装Virtualbox虚拟机,笔记本cpu为i5-2450m.虚拟机上安装Ubuntu16.04 ...
- oops linux 内核,Linux内核的Oops
Bingo!在Oops的帮助下我们很快就解决了问题. 我们再回过头来检查一下上面的Oops,看看Linux内核还有没有给我们留下其他的有用信息. Oops: 0002 [#1] 这里面,0002表示O ...
最新文章
- php输出报错Message: Array to string conversion
- 查看node状态_第六章 无限可能,神器降临——Node-RED
- [转载] 晓说——第31期:无比强大的美国工会
- Git使用技巧(3)-- 远程操作
- Easyui入门视频教程 第11集---Window的使用
- Python爬虫进阶三之Scrapy框架安装配置
- ES6之Module 的加载实现(2)
- 了解 SharePoint 2010 开发中的关键点
- 消息中间件系列(八):Kafka、RocketMQ、RabbitMQ等的优劣势比较
- WordPress 极简约风格smalls-one主题
- 部分手机浏览器存在将ajax请求当成广告过滤的情况,及解决方案
- caffe的python接口学习(2):生成solver文件
- flying saucer技术生成pdf文档
- iOS--通过assetURL获取到视频
- AAAI2021 | 在手机上实现19FPS实时的YOLObile目标检测,准确率超高
- JS(fullpage)的使用
- 不伤原图电脑在线去水印网站
- mysql 查询分析器_mysql查询分析工具|mysql查询分析器(MySQL Query Browser)下载v1.1.20 官方版_ IT猫扑网...
- 超导系统与服务器断开,HT一7超导托卡马克总控系统的设计与实现.pdf
- 梦三国大区服务器位置,《梦三国2》军团大盘点 指点江山论各大区军团分布哪家强?...
热门文章
- 现在用云服务器建站还是用虚拟主机建站好?
- thinkphp + 美图秀秀api 实现图片裁切上传,带数据库
- 【语义分割专题】语义分割相关工作--PSPNet
- 如何运用python爬游戏皮肤_用Python爬取英雄联盟(lol)全部皮肤
- 给张云成的留言 20120223
- python numpy创建矩阵、并归一化_NumPy数据的归一化
- 【Kotlin】字符串操作 ① ( 截取字符串函数 substring | 拆分字符串函数 split | 解构语法特性 )
- mysql 模糊查询like优化方案(亲测)
- solidworks2019无法连接到服务器(-15...)或(-8...)
- python zipfile extract 解压 中文文件名