图解linux内核学习笔记
第2章 数据结构和设计模式
2.1.1 一对一关系
//指针
struct entity_a{
struct entity_b * b;
};
struct entity_b{
struct entity_a * a;
};
//内嵌(包含)
struct entity_a{
struct entity_b b;
};
第二种方式的主要优点是对一对一关系体现得比较清晰,同时也方便管理, 因为通过container_of宏可以由b计算出 a 的位置,同时节省了指针的空间。
然而第二种方式本身意味着若a包含b (b是a的一部分),并不一定是最好的,要视逻辑而定。比如男人和妻子,在我国《婚姻法》上是一对一的,如果采用内嵌的方式首先造成的是逻辑混乱,男人结构体中多了女人这个不属于男人的成员;其次,并不是每个男人都有妻子,有些是单身,用指针表示就是NULL, 内嵌无疑浪费了空间。所以,要满足逻辑合理,当有a就有b这个条件时采用这种方式才是比较恰当的。
container_of
是 Linux 内核(以及很多 C 项目)里最常见、最基础的一个宏:“从结构体成员的地址反推出整个结构体的地址”。
它在内核链表中几乎无处不在,所有 list_for_each_entry* 都靠它把 struct list_head 变回你真正的数据结构。
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); \
})

实例代码如下:
#include<stdio.h>
#include<stddef.h>
#include<stdlib.h>
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)
/*ptr 成员指针
* type 结构体 比如struct Stu
* member 成员变量,跟指针对应
* */
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (const typeof( ((type *)0)->member ) *)(ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
typedef struct Stu{
int age;
char name[10];
int id;
unsigned long phone_num;
}*p_stu,str_stu;
void print_all(void *p_str)
{
p_stu m1p_stu = NULL;
m1p_stu = container_of(p_str,struct Stu,age);
printf("age:%d\n",m1p_stu->age);
printf("name:%s\n",m1p_stu->name);
printf("id:%d\n",m1p_stu->id);
printf("phone_num:%d\n",m1p_stu->phone_num);
}
void main(void)
{
p_stu m_stu = (p_stu)malloc(sizeof(str_stu));
m_stu->age = 25;
m_stu->id = 1;
m_stu->name[0]='w';
m_stu->name[1]='e';
m_stu->name[2]='i';
m_stu->name[3]='q';
m_stu->name[4]='i';
m_stu->name[5]='f';
m_stu->name[6]='a';
m_stu->name[7]='\0';
m_stu->phone_num=13267;
/*传结构体成员指针进去*/
print_all(&m_stu->age);
printf("main end\n");
if(m_stu!=NULL)
free(m_stu);
}
程序输出:
age:25
name:weiqifa
id:1
phone_num:13267
main end
参考文献:https://zhuanlan.zhihu.com/p/54932270 写得很好
2.1.2 一对多关系
主要讲解内核链表 list
参考文献:https://zhuanlan.zhihu.com/p/450778696

浙公网安备 33010602011771号