在Linux内核编程中,READ_ONCE 宏用于确保从内存中读取一个变量的值时,编译器不会对这个读取操作进行优化,从而保证了读取操作的原子性。...这个宏通常在需要防止编译器优化、多线程或中断上下文中使用,以确保数据的一致性和正确性。...以下是 READ_ONCE 宏的定义及其解释: #define READ_ONCE(x) (*(volatile typeof(x) *)&(x)) 解释: typeof(x):这是一个GNU扩展,用于获取变量...这种定义方式确保了变量在读取时不会被编译器优化掉,从而在并发环境下或者硬件访问场景下提供更安全的访问。...对于写操作,Linux内核中有对应的 WRITE_ONCE 宏,其定义方式和用途类似。 通过这种方式,可以在内核编程中更安全地访问共享变量,避免数据竞争和内存一致性问题。
文章目录 回顾 问题具象化 上工具 offsetof 实例分析 container_of 实例解析 offsetof 原理 container_of 原理 参考 回顾 上一篇我们讲到内核链表和普通链表的区别...,就有小伙伴追问:内核链表是怎么通过指针域来访问数据域的呢?...上工具 这时候,就用到了 linux 内核中提供的两个宏了 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define...container_of 宏用来在给定一个变量的结构体类型,和这个变量的某个成员的地址的条件下,计算出这个变量的地址。...led 变量,不过这里我们假设 led 变量是在别处定义的,我们拿不到。
list_entry()有着内核第一宏的美称,它被设计用来通过结构体成员的指针来返回结构体的指针。现在就让我们通过一步步的分析,来揭开它的神秘面纱,感受内核第一宏设计的精妙之处。...整理分析的思路 list_entry()在内核源代码/include/linux目录下的list.h中被定义,如下: ?...container_of定义在/include/linux/kernel.h中,定义如下: ? 我们发现,在container_of的定义中,又出现一个新的宏offsetof。...offsetof定义在/include/linux/stddef.h中,定义如下: ?...现在我们回到最初的出发点———list _entry(),也就明白了为什么它被称作内核第一宏了。
#define offsetof ( TYPE, MEMBER) \
文章目录 一、操作系统需要满足的要素 二、宏内核 三、微内核 四、Linux 内核动态加载机制 一、操作系统需要满足的要素 ---- 电脑上运行的 操作系统 , 是一个 软件 ; 设备管理 : 操作系统需要...---- 宏内核 : 内核代码 编译成 二进制文件 , 内核 运行在 一个 大内核 地址空间 中 , 可以 直接 访问 , 调用 内核代码 , 这种内核优点是 效率高 , 性能强 ; 下图中 , 最上层是..." 系统调用 " , 中间是 " 宏内核 " , 最下方是 硬件层 ; 宏内核优点 : 设计简单 , 性能高 ; 三、微内核 ---- 微内核 : 将 操作系统 拆分成 多个 独立功能模块 , 这些...进行通信 , 微内核优点 : 稳定性好 , 实时性好 ; 微内核缺点 : 高度模块化 , 模块之间只能通过消息传递信息 , 效率低 ; 四、Linux 内核动态加载机制 ---- Linux 内核模块动态加载...: Linux 内核 使用了 模块设计 , 可以进行 动态加载 内核模块 ; Linux 内核的 核心实现 , 设备驱动实现 , 可以 编译成一个独立模块 , 这些独立模块可以被编译成 独立的目标文件
1、前面说的 我在好几年前读linux 驱动代码的时候看到这个宏,百度了好久,知道怎么用了,但是对实现过程和原理还是一知半解。...container_of宏 在linux内核代码里面使用次数非常非常多,对于喜欢linux编程的同学来说,了解其实现方法,对以后看内核代码,写内核驱动的帮助都非常大,当然,我不是说了解这个就可以为所欲为了...这里简单说下,传进来的h一定在其他地方定义并且操作系统分配了内存空间,h分配了空间,说明他的老爸也有内存了,要不然你顺藤摸瓜摸到一个NULL就傻逼了。...4.5、const int* p的作用 上面的宏定义里面还有一个小知识点 const typeof( ((type *)0)->member ) *__mptr 上面的代码可以简写成 const int...6、实例代码 经过上面的解释,至少对这个宏有感觉了吧,写个代码来测试一下,让自己与代码融合为一体,这样才能做到人码合一的境界。
操作系统的内核设计一直都存在两个阵营,一个是宏内核,另一个是微内核。 操作系统也属于软件的范畴,有两大功能: 1. 管理系统上的硬件资源。 2. 为应用程序提供执行环境。...宏内核 所有的内核代码都编译成一个二进制文件,所有的内核代码都运行在一个大内核地址空间里,内核代码可以直接调用和访问,效率高且性能好。...微内核 把操作系统分成多个独立的功能模块,每个功能模块之间访问需要通过消息来完成,因此效率没那么高。 宏内核和微内核的架构图如下: ?...Linus当初在设计Linux操作系统时采用的是宏内核架构。但是Linux在20年来的发展中,不断融入微内核的一些精华设计,如模块化设计,抢占式内核,动态加载内核模块等。...Linux内核中很多核心的实现或者设备驱动的实现都可以编译成一个个单独的模块。模块是被编译成的一个目标文件,并且可以在运行时的内核上动态加载和卸载。
如何移植并使用Linux内核的通用链表(附完整代码实现)中提到的为什么在结构体中要把 struct list_head放在首位。...container_of宏的作用是通过结构体内某个成员变量的地址和该变量名,以及结构体类型。找到该结构体变量的地址。...offsetof(type, member)) ((size_t) &((TYPE*)0)->MEMBER) size_t是标准C库中定义的,在32位架构中被普遍定义为: typedef unsigned...int size_t; 而在64位架构中被定义为: typedef unsigned long size_t; 可以从定义中看到,size_t是一个非负数,所以size_t通常用来计数(因为计数不需要负数区...): for(size_t i=0;i<300;i++) 为了使程序有很好的移植性,因此内核使用size_t和,而不是int,unsigned。
1.无参数的宏定义 #define _CRT_SECURE_NO_WARNINGS #include #include #include /.../宏 常量 //1.不重视作用域 //2.可以用undef卸载宏 //3.宏常量 没有数据类型 void test() { #define MAX 100 } int main() { test();...int a = MAX; printf("%d", a); return 0; } 说明: 2.带参数的宏定义(宏函数) #define _CRT_SECURE_NO_WARNINGS...#include #include #include //宏 函数 //1.将短小,频繁使用的函数写成宏函数 //2.加括号保证运算完整性 //...函数 //1.将短小,频繁使用的函数写成宏函数 //2.加括号保证运算完整性 //3.优点:空间换时间 #define SUM(x,y) ((x)+(y)) void test() { int ret
简介: 宏是一种抽象(Abstraction),它根据一系列预定义的规则替换一定的文本模式。解释器或编译器在遇到宏时会自动进行这一模式替换。...在linux中大量的使用宏,使得代码简洁且技巧性很高,本篇就主要记录一下在linux中比较常用的几种用法。...1.定义固定值,便于快速修改 #define MAX_SIZE 1024 这种例子比较简单且很常用,主要是用于对常量的修饰,避免定义变量,减少对内存的消耗。...printk(KERN_ERR LOG_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args) 一般一个文件会定义一种log输出的宏函数,其实就是对printk.../Makefile obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o 内核的裁剪就是依靠宏函数实现的。
对象宏 #define M_PI 3.1415926535 double r = 1.0; double circlePerimeter = 2 * M_PI * r; // => double circlePerimeter...= 2 * 3.1415926535 * r ## 函数宏 #define FUNC(x) x NSLog(@"Hello %@", FUNC("world"); // => NSLog(@"Hello
C++宏定义 学过C语言的读者,对宏定义应该不陌生,同样在C++中,也可以用宏定义命令将一个指定的标识符来代表一个字符串,宏定义的作用一般是用一个短的名字代表一个长的字符串。...一般形式为: #define 标识符 字符串 定义PI的符号常量: #define PI 3.14 在C++中还可以用#define命令定义带参数的宏定义,一般形式为: #define 宏名(参数表)...中基本上已不再用#define 命令定义宏了,宏定义主要用于条件编译中。...经典案例:C++宏定义求面积,要求可以手动输入长和宽。...C++宏定义求面积 更多案例可以go公众号:C语言入门到精通
前面题目主要是自定义函数的题,相信经过这些题目的训练,大家对自定义函数的理解想必更近了一步。...接下来呢,我们主要来练习跟自定义函数异曲同工的宏定义,先看看下面这题 题目描述 三角形面积=SQRT(S*(S-a)*(S-b)*(S-c)) 其中S=(a+b+c)/2,a、b、c为三角形的三边。...定义两个带参的宏,一个用来求area, 另一个宏用来求S。 写程序,在程序中用带实参的宏名来求面积area。 输入 a b c三角形的三条边,可以是小数。...输出 三角形面积,保留3位小数 样例输入 3 4 5 样例输出 6.000 PS:有句话很经典哦“宏定义只是简单的字符替换哦” 详细题解见C语言网题库1038题 明天就是咱们C语言网有奖月赛的日子了,希望大家积极参加哦
宏内核和微内核最大的区别就是,宏内核的用户服务和内核服务都保存在相同的地址空间中,它们都由内核进行统一管理,而微内核的用户服务和内核服务会保存在不同的地址空间中,下图可以很好的解释这一点。...现代成功的 CPU 设计包括这两种技术中的任何一种,就像 Linux 内核是微内核和宏内核的混合产品一样。...可能有些人认为 Linux 它不就是个宏内核结构么,但实际上 Linux 不单单只是一个纯碎的集成内核。为什么 Linux 会使用单内核(此处叫单内核有点应景)结构呢?我猜有下面几个因素。...Linux 是一个借鉴了微内核精髓的宏内核结构,Linux 支持模块化的设计、抢占式内核、对内核线程的支持以及动态加载内核模块的能力。...猎报安全提供主机服务器远程运维和安全监控实时告警,有运维监控、威xie检测、自定义告警、订阅推送之类的功能,还没有广告。图片值得一提的是这款软件所占内存小到可以忽略不计,安装之后主机设备零负担。
1 微内核与宏内核有何异同 微内核——内核只提供任务调度和进程间通信(IPC),当然还包括为任务调度提供服务的系统时钟、中断以及内存管理等最基本的硬件管理能能力。...代表OS:L4系列微内核。 宏内核——也称为单内核,所有的系统服务,包括任务调度,系统资源访问等等,都由内核态通过系统调用向用户态提供系统服务。...一张图说明它们的区别: 总结seL4微内核的优缺点: 优势: 安全性好、可移植性好、灵活性高、容易debug 劣势: 性能低 2 微内核的发展史 第一代微内核: 目标是用于解决Unix的可维护性等问题...第二代微内核: 目标是解决第一代微内核的性能问题。代表是Liedtke的L3和L4。主要贡献是通过改进IPC机制,大幅提高了性能,并支持运行Linux,即L4 Linux(虚拟化)。...第三代微内核: 目标是解决第二代微内核的安全性问题,引用了形式化验证,号称世界上最安全的内核OS。代表是OKL4、seL4(我们后面的研究重点)。
内核开发者也比较nice,在内核源码samples/trace_events目录下就有这么一个例子。 其中文件一共有三个: ? 这个例子以内核模块的形式存在,所以只要执行make就可以编译完成。...那么这些函数是怎么定义的呢? TRACE_EVENT定义 看完了例子,我们就该看代码实现了。讲真,这是我见过的最长的宏展开了。...可以看到,一个trace event的定义需要涉及到起码两个头文件。 史上最长宏定义 你以为就这么简单吗?当然不是,作为有多年阅读c语言代码的老司机,看到真正的定义,我都差点没有吐出来。。。...不过相信我,你可能不太会愿意去看这个(捂脸) 回过头来再看这展开,让我们来总结一下这个过程: 一共包含了两个头文件:linux/tracepoint.h 和 trace/define_trace.h 在...或者说,看了可能也不知道这些宏展开究竟定义了些什么? 帮人帮到底,送佛送到西 既然都帮大家做了宏展开,那我就干脆再用一张图展示一下这么多宏定义究竟定义了些什么。 ? ?
四、#define定义宏 #define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。...a + 1) ); 这里还有一个宏定义: #define DOUBLE(x) (x) + (x) 定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。...这个问题,的解决办法是在宏定义表达式两边加上一对括号就可以了。...当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。...最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。 注意: 1. 宏参数和#define 定义中可以出现其他#define定义的符号。
C语言中宏定义分两种,无参的宏和有参的宏 1.无参数的宏 无参数宏定义的一般形式为: #define name value//name是你起的名字,就跟起函数名一样,value是你要给这个名字赋予什么值...宏定义在源程序中单独另起一行,换行符是宏定义的结束标志(不能在末尾加分号)。如果一个宏定义太长,一行不 够时,可采用续行的方法。续行是在键人回车符之前先键入符号"/"。...宏定义的有效范围称为宏定义名的辖域(也可以叫做生命周期,类似于变量的生命周期),辖域从宏定义的定义结束处开始到其所在的源程序文件末尾。宏定义名的辖域不受分程序结构的影响。...可以用预处理命令#undef终止宏定义名的辖域。 3....如有必要,宏名可被重复定义。被重复定义后,宏名原先的意义被新意义所代替。
宏定义的作用相当于给指定的字符串起了一个别名。...不带参数的宏的定义方式如下(这也是我们经常用到的宏定义) #define 宏名 字符串 //没有分号,说没有分号倒不如说最好不要加分号 这里说下原因吧:因为宏定义它并不是C语言的语句,所以不用加分号...定义宏 #define 机制包括了一个规则,允许把参数替换到文本当中去,这种实现操作通常被称之为是宏(macro) 或者是 定义宏(define macro) 带参数的宏定义方式如下格式...此时编译器就相当于未定义标识符NUM了说的简单点相当于不存在了,注:是在取消宏定义之后的语句当中的。 拓展知识点⇥宏可以在任意地方使用。...宏的作用范围:从定义出开始往后它都是有效的。
在C语言中,有这样一个特殊的宏,叫offsetof,它的功能是啥呢?
领取专属 10元无门槛券
手把手带您无忧上云