Linux内核数据结构之链表

34 篇文章 0 订阅
7 篇文章 0 订阅

Linux内核数据结构之链表

在Linux内核中,链表的实现和运用独树一帜。

struct list_head {
    struct list_head *next, *prev;
};

linux内核采用这种双向链表的结构作为标准链表,以提供最大的灵活性。

我们将某种数据结构存放到链表中通常是在数据结构中嵌入一个链表指针,例如:

struct A {
    int a;
    int b;
    struct A *prev;
    struct A *next;
};

linux内核是将链表节点放入数据结构中:

struct list_head {
    struct list_head *next, *prev;
};

struct A {
    int a;
    int b;
    struct list_head list;
};

随之而来的问题就是如何由节点访问到数据结构中的其他成员。linux内核提供了container_of()方法,让我们能够方便的从链表指针找到父结构对象。

// ptr: 父结构中的成员的指针(在链表中,就是节点指针)
// type: 父结构类型
// member: 成员(在链表中是节点)
#define container_of(ptr, type, member) ({                   \
	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
	(type *)( (char *)__mptr - offsetof(type,member) );})
// 首先((type *)0)将0转换成type类型的指针,这个指针的数值为0;
// __mptr 获得成员指针;
// offsetof(type,member)获得成员到父结构的偏移;
// (type *)( (char *)__mptr - offsetof(type,member) ); 得到父结构指针;

以下面代码以及图示可以更好的理解。

#include <iostream>
#include <string>

using namespace std;

// ptr: 父结构中的成员的指针(在链表中,就是节点指针)
// type: 父结构类型
// member: 成员(在链表中是节点)
#define container_of(ptr, type, member) ({                   \
	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
	(type *)( (char *)__mptr - offsetof(type,member) );})

struct list_head {
    struct list_head *next, *prev;
};

struct Person {
    int age;
    bool sex;
    string name = "adfgdfgb";
    double height;
    list_head list;
};

int main(int argc, char** argv)
{
    Person p1 = {12, true, "Tom", 1.78};
    Person p2 = {19, false, "Jony", 1.66};
    p1.list.prev = nullptr;
    p1.list.next = &p2.list;
    p2.list.prev = &p1.list;
    p2.list.next = nullptr;

    if (container_of(p2.list.prev, Person, list) == &p1) {
        cout << "ok" << endl;
        cout << container_of(p2.list.prev, Person, list)->age << endl;
    }
    return 0;
}

结合代码,看图,实质上就是理解container_of是怎么求P1的地址的。其实就是? + offsetof = _mptr => ? = _mptr - offsetof

container_of在C++中应用有一个严格的条件:结构中的成员是平凡类型或是标准布局类型,简单一点说就是,结构中的成员在编译期各个的相对位置就被ABI固定了,如果某个成员在结构中的大小可变,那么这个偏移就无法固定,则无法找到父结构。string虽然存放不定长的字符串,但是一个标准布局类型,字符串是分配在堆上,结构中存放的是它的地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值