使用Linux内核中的container_of宏来实现数据结构中的指针偏移

作者:三明麻将开发公司 阅读:37 次 发布时间:2025-07-21 16:29:16

摘要:Linux内核源码中的container_of宏是一个十分有用的工具,它允许我们实现一些复杂的数据结构设计。这个宏需要一个类型、结构体中成员的名字和这个成员的地址,就可以根据结构体的地址反向计算出整个结构体的地址,从而实现了指针偏移。下面,我们将详细介绍container_of的实现...

Linux内核源码中的container_of宏是一个十分有用的工具,它允许我们实现一些复杂的数据结构设计。这个宏需要一个类型、结构体中成员的名字和这个成员的地址,就可以根据结构体的地址反向计算出整个结构体的地址,从而实现了指针偏移。下面,我们将详细介绍container_of的实现方式、原理以及在数据结构设计中的应用。

使用Linux内核中的container_of宏来实现数据结构中的指针偏移

一、container_of的实现方式

具体来说,container_of宏的定义如下:

#define container_of(ptr, type, member) ({ \

const typeof( ((type *)0)->member ) *__mptr = (ptr); \

(type *)( (char *)__mptr - offsetof(type,member) );})

从代码中可以看到,container_of宏被定义成了一个匿名的内联函数(inline),它有3个参数:指向成员的指针ptr,成员所属的结构体类型type,以及成员在结构体中的名字member。具体来说,container_of宏执行的过程如下:

1. 创建一个指向成员的指针__mptr,其用途会在下一步骤中描述。

2. 获取成员变量的类型,并初始化指向成员的指针__mptr:

__mptr = (ptr)

这里,我们使用了typeof运算符获取了成员变量的类型,并且将指向成员的指针赋值为ptr。

3. 通过offsetof宏获取成员变量在结构体中的偏移量,并计算出结构体的地址:

(char *)__mptr - offsetof(type, member)

这里,我们使用了offsetof宏计算出成员变量在结构体中的偏移量,并将成员变量的指针强制转化为char类型的指针,以便进行指针运算。由于我们知道成员变量的地址,所以我们可以推算出结构体地址,这就是说,我们需要从成员变量的地址减去其在结构体中的偏移量。

4. 返回结构体地址。

(type *)( (char *)__mptr - offsetof(type,member) )

这里,我们将计算出的结构体地址强制转换为type类型的指针,并作为container_of宏的返回值。

二、container_of的原理

这里,我们来深入探讨一下container_of宏的原理。在实际应用中,我们在定义数据结构时,通常会将在结构体中的每个成员和结构体类型关联起来。例如:

struct list_node {

int data;

struct list_node *next;

};

在这里,我们定义数据结构list_node,其包含了一个整型的data和一个指向下一个节点的指针next。由于next指针是指向链表的下一个节点,所以我们无法在结构体之间使用next进行直接的偏移运算。为了解决这个问题,我们需要使用container_of宏。

对于一个指向链表节点的指针list_node_ptr,我们可以使用container_of宏将其转换为list_node结构体的指针。但是,这个宏的原理是什么呢?我们假设list_node_ptr指向了链表节点的第二个元素(下标为1),那么使用container_of宏对其进行计算后,只需要减去偏移量即可得到链表节点的起始地址,从而获得上一个节点的指针。因此,container_of宏的原理就是基于成员和结构体类型之间的关联,来实现反向计算结构体地址的目的。

三、container_of在数据结构设计中的应用

在数据结构设计中,使用container_of宏可以让我们通过其成员进行反向计算,快速地找到数据结构中的起点,从而更有效地对其进行操作。下面,我们将具体介绍一些应用场景。

1. 利用container_of宏实现树形结构

在树形结构中,子节点可以通过指针指向父节点,但是访问父节点的指针并不直接可用,这就需要使用container_of宏。

下面是一个简单的示例代码:

struct bt_node {

int data;

struct bt_node *lchild, *rchild, *father;

};

typedef struct bt_node BTNode;

BTNode * get_root(BTNode * node) {

while (node->father != NULL) {

node = container_of(node->father, BTNode, lchild);

}

return node;

}

在get_root函数中,我们通过while循环和container_of宏来追溯节点的祖先,直到到达根节点。首先,我们通过container_of宏获取节点的父节点指针,然后迭代地向上寻找父节点,直到节点的父节点为空指针为止。在这个过程中,container_of宏充当了计算节点地址的作用。

2. 利用container_of宏实现链表结构

链表结构如同树形结构一样,节点之间关联起来通过指针实现,通过container_of宏可以更方便地访问链表节点的前一个节点。

下面是一个简单的示例代码:

struct list_node {

char *data;

struct list_node *next;

};

int delete_node(struct list_node *node) {

struct list_node *prev = container_of(node->data, struct list_node, data);

prev->next = node->next;

free(node->data);

free(node);

return 0;

}

在delete_node函数中,我们使用container_of宏来获取链表节点的前一个节点,从而方便地访问链表。这里,我们首先通过container_of宏获取到链表节点的前一个节点的指针,然后将指针改变为node节点的下一个节点的指针,从而避免了在链表中存储前一个节点的指针的需要。

四、总结

以上是关于container_of宏的介绍,container_of宏的原理是基于成员和结构体类型之间的关联,来实现反向计算结构体地址的目的。在数据结构设计中,使用container_of宏可以让我们快速地找到数据结构中的起点,同时避免了在数据结构中存储前一个节点或前一个元素的指针。作为C语言的一个特性,container_of宏在操作系统和驱动开发中大量使用,并为实现复杂数据结构提供重要的支持。

  • 原标题:使用Linux内核中的container_of宏来实现数据结构中的指针偏移

  • 本文链接:https://qipaikaifa.cn/qpzx/3864.html

  • 本文由三明麻将开发公司中天华智网小编,整理排版发布,转载请注明出处。部分文章图片来源于网络,如有侵权,请与中天华智网联系删除。
  • 微信二维码

    ZTHZ2028

    长按复制微信号,添加好友

    微信联系

    在线咨询

    点击这里给我发消息QQ客服专员


    点击这里给我发消息电话客服专员


    在线咨询

    免费通话


    24h咨询☎️:157-1842-0347


    🔺🔺 棋牌游戏开发24H咨询电话 🔺🔺

    免费通话
    返回顶部