文章目录

  • 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_ERRNOerr.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. 取绝对值
  2. 取反码,也就是对每一位取反
  3. 对反码加1,得到补码

以char型为例,-1在内存中的表示计算方法如下:

#mermaid-svg-KzKzS48DCiQwd0Nw {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-KzKzS48DCiQwd0Nw .error-icon{fill:#552222;}#mermaid-svg-KzKzS48DCiQwd0Nw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KzKzS48DCiQwd0Nw .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-KzKzS48DCiQwd0Nw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KzKzS48DCiQwd0Nw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KzKzS48DCiQwd0Nw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KzKzS48DCiQwd0Nw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KzKzS48DCiQwd0Nw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KzKzS48DCiQwd0Nw .marker.cross{stroke:#333333;}#mermaid-svg-KzKzS48DCiQwd0Nw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KzKzS48DCiQwd0Nw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KzKzS48DCiQwd0Nw .cluster-label text{fill:#333;}#mermaid-svg-KzKzS48DCiQwd0Nw .cluster-label span{color:#333;}#mermaid-svg-KzKzS48DCiQwd0Nw .label text,#mermaid-svg-KzKzS48DCiQwd0Nw span{fill:#333;color:#333;}#mermaid-svg-KzKzS48DCiQwd0Nw .node rect,#mermaid-svg-KzKzS48DCiQwd0Nw .node circle,#mermaid-svg-KzKzS48DCiQwd0Nw .node ellipse,#mermaid-svg-KzKzS48DCiQwd0Nw .node polygon,#mermaid-svg-KzKzS48DCiQwd0Nw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KzKzS48DCiQwd0Nw .node .label{text-align:center;}#mermaid-svg-KzKzS48DCiQwd0Nw .node.clickable{cursor:pointer;}#mermaid-svg-KzKzS48DCiQwd0Nw .arrowheadPath{fill:#333333;}#mermaid-svg-KzKzS48DCiQwd0Nw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KzKzS48DCiQwd0Nw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KzKzS48DCiQwd0Nw .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-KzKzS48DCiQwd0Nw .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-KzKzS48DCiQwd0Nw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KzKzS48DCiQwd0Nw .cluster text{fill:#333;}#mermaid-svg-KzKzS48DCiQwd0Nw .cluster span{color:#333;}#mermaid-svg-KzKzS48DCiQwd0Nw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KzKzS48DCiQwd0Nw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

取反码
反码加1
0000 0001
1111 1110
1111 1111

关于为什么使用补码存储数据,可以参整数在内存中是如何存储的,为什么它堪称天才般的设计。

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简介相关推荐

  1. [linux内核][LINUX内核编程]学习笔记(一)

    linux内核使用bitmap相关  1,声明一个bitmap数组,可以表示100个bit,数组名字是bitmap [cpp] view plaincopy DECLARE_BITMAP(bitmap ...

  2. linux 内核 linux kernel travel

    linux 内核 kernel_核 travel_旅行 linux kernel travel linux 2.6 1 hellomod.c 001 // hello world driver for ...

  3. 复制linux内核,linux内核写时复制机制源代码解读

    作者简介 写时复制技术(一下简称COW)是linux内核比较重要的一种机制,我们都知道:父进程fork子进程的时候,子进程会和父进程会以只读的方式共享所有私有的可写页,当有一方将要写的时候会发生COW ...

  4. 生效linux内核,Linux内核

    内核 单内核体系设计.但充分借鉴了微内核设计体系的优点,为内核引入模块化机制. 内核组成部分: kernel:内核核心,一般为bzimage,通常在/boot目录下,名称为vmlinuz kernel ...

  5. 哪些系统使用了linux内核,Linux操作系统有哪些

    Linux操作系统有哪些 导语:Linux操作系统诞生于1991 年的10月5 日.Linux存在着许多不同的Linux版本,但它们都使用了Linux内核.Linux可安装在各种计算机硬件设备中,比如 ...

  6. 嵌入式烧写Linux内核,嵌入式linux 内核和根文件系统烧写方式简介

    总体来说,嵌入式Linux内核和根文件的引导与PC机差不多. 嵌入式linux内核和根文件系统可以存放在各种可能的存储设备中,一般情况下我们将内核和根文件系统直接烧入到Flash中(包括NOR和NAN ...

  7. gcc与linux内核,linux内核版本及其编译的gcc版本

    以前不知道,现在用crosstool-ng编译了5.2.0版本的arm-linu-gcc,再编译之前的linux-3.15.4发现会提示 include/linux/compiler-gcc.h:10 ...

  8. 如果查看linux内核,linux怎么查看内核版本

    有朋友在使用Linux的过程中要查看Linux的内核版本号,这要怎么看呢?也有朋友文要怎么查看linux系统版本信息呢?下面和小编一起了解一下吧. 一.查看linux内核版本号 1:登录linux,在 ...

  9. 学做Linux内核,Linux内核学习(3) 最小系统制做2 busybox制做initrd.img和根文件系统...

    busybox制做initrd.img和根文件系统 (一)开发环境介绍 1.使用win7_64的笔记本安装Virtualbox虚拟机,笔记本cpu为i5-2450m.虚拟机上安装Ubuntu16.04 ...

  10. oops linux 内核,Linux内核的Oops

    Bingo!在Oops的帮助下我们很快就解决了问题. 我们再回过头来检查一下上面的Oops,看看Linux内核还有没有给我们留下其他的有用信息. Oops: 0002 [#1] 这里面,0002表示O ...

最新文章

  1. php输出报错Message: Array to string conversion
  2. 查看node状态_第六章 无限可能,神器降临——Node-RED
  3. [转载] 晓说——第31期:无比强大的美国工会
  4. Git使用技巧(3)-- 远程操作
  5. Easyui入门视频教程 第11集---Window的使用
  6. Python爬虫进阶三之Scrapy框架安装配置
  7. ES6之Module 的加载实现(2)
  8. 了解 SharePoint 2010 开发中的关键点
  9. 消息中间件系列(八):Kafka、RocketMQ、RabbitMQ等的优劣势比较
  10. WordPress 极简约风格smalls-one主题
  11. 部分手机浏览器存在将ajax请求当成广告过滤的情况,及解决方案
  12. caffe的python接口学习(2):生成solver文件
  13. flying saucer技术生成pdf文档
  14. iOS--通过assetURL获取到视频
  15. AAAI2021 | 在手机上实现19FPS实时的YOLObile目标检测,准确率超高
  16. JS(fullpage)的使用
  17. 不伤原图电脑在线去水印网站
  18. mysql 查询分析器_mysql查询分析工具|mysql查询分析器(MySQL Query Browser)下载v1.1.20 官方版_ IT猫扑网...
  19. 超导系统与服务器断开,HT一7超导托卡马克总控系统的设计与实现.pdf
  20. 梦三国大区服务器位置,《梦三国2》军团大盘点 指点江山论各大区军团分布哪家强?...

热门文章

  1. 现在用云服务器建站还是用虚拟主机建站好?
  2. thinkphp + 美图秀秀api 实现图片裁切上传,带数据库
  3. 【语义分割专题】语义分割相关工作--PSPNet
  4. 如何运用python爬游戏皮肤_用Python爬取英雄联盟(lol)全部皮肤
  5. 给张云成的留言 20120223
  6. python numpy创建矩阵、并归一化_NumPy数据的归一化
  7. 【Kotlin】字符串操作 ① ( 截取字符串函数 substring | 拆分字符串函数 split | 解构语法特性 )
  8. mysql 模糊查询like优化方案(亲测)
  9. solidworks2019无法连接到服务器(-15...)或(-8...)
  10. python zipfile extract 解压 中文文件名