既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
本文参考《Linux操作系统原理与应用》以及如下博客:
https://blog.csdn.net/this_capslock/article/details/39189947
给定一个结构体定义type,这个结构体中某个成员变量的名字member以及它的地址ptr,如何得到包含此成员变量的结构体的地址?即通过结构体成员的地址获取结构体变量的地址?
为了便于分析,我们给出一个实例来说明
struct father_t {
int a;
char *b;
double c;
}f;
根据C语言对struct类型的存储特性,我们可以画这么一个图示:
通过分析图示,我们可以看出,我们只需要把当前知道的成员变量的地址ptr,减去它在结构体当中相对偏移4就的到了结构体的地址(ptr-4)。
一、list_entry宏分析
#define list\_entry(ptr, type, member) \
((type \*)( (char \*)(ptr) - (unsigned long)(&((type\*)0)->member)))
如下图,指针ptr指向结构体type中的成员member;通过指针ptr,返回结构体type的起始地址,也就是list_entry返回指向type类型的指针。
分析:
((type *)0)->member
把0地址转换为type结构的指针,然后获取该结构中member域的指针,也就是获得了member在type结构中的偏移量(char *)(ptr)
求出的是ptr的绝对地址- 二者相减,于是得到type类型结构体的起始地址
二、typeof学习
typeof关键字是C语言中的一个新扩展,这个特性在linux内核中应用非常广泛。
typeof 是自动推导后面 ( ) 里的数据类型,所以 typeof(int *) 直接推导出了 int * 型
这样的话,当遇到一个非常复杂的表达式我们很难推断其类型的时候,typeof 就很有用了。另外有一点要注意:typeof 是 GNU C 标准里特有的扩展,标准的 ISO C 并没有这个关键字,所以在编译的时候不能加任何 ISO 的 C 标准选项( -std=c90 ),否则会报错,此时把 -std=c90 改成 -std=gnu90 即 GNU 的标准即可。
三、代码
首先看看Linus的实现:
#define offsetof(TYPE, MEMBER) ((size\_t) &((TYPE \*)0)->MEMBER)
/**
* container_of - 通过结构体的一个成员获取容器结构体的指针
* @ptr: 指向成员的指针。
* @type: 成员所嵌入的容器结构体类型。
* @member: 结构体中的成员名。
*/
#define container\_of(ptr, type, member) ({
const typeof( ((type \*)0)->member ) \*\_\_mptr = (ptr);
(type \*)( (char \*)\_\_mptr - offsetof(type,member) );
})
(1)定义一个中间变量__mptr,它等于提供给宏的参数ptr,也就是指向某个成员的指针。这个中间变量的命名意义是:
“__”代表内部使用,内核编程中常常这么做;“m”代表middle。
为了避免对 ptr及prt指向的内容造成破坏,这里不直接使用 ptr 而要多多加一个__mptr。
(2)把__mptr转换成 char *类型,因为offsetof得到的偏移量是以字节为单位。两者相减得到结构体的起始位置,再强制转 换成type类型。
这个宏的作用,就是通过一个容器(结构体)中某个成员的指针得到指向这个容器(结构体)的指针,简单的说就是通过成员 找容器。
这里代码进行验证:
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**