container_of使用小结

本文详细解析了C语言中offsetof和container_of宏的工作原理及其应用。通过具体示例介绍了如何利用这两个宏进行结构体成员定位及通过成员指针获取结构体指针,对理解Linux内核源码尤其有帮助。

 先上演示代码

#include <stdio.h>
#include <stdlib.h>

/* offsetof example */
#include <stddef.h>     /* offsetof */

//#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) );})

typedef struct student_info
{
    int  id;
    char name[10];
    int  age;
}student_info;

#define DEBUG_COUT(var) do{printf(#var"= %d\n",(int)var);}while(0)
#define DEBUG_POINT(var) do{printf(#var"= %p\n",var);}while(0)    
int main(void)
{

    printf ("************offsetof example************\n");
    DEBUG_COUT(offsetof(student_info,id)); 
    DEBUG_COUT(offsetof(student_info,name)); 
    DEBUG_COUT(offsetof(student_info,age));     
    printf ("************container_of example************\n");
    student_info *stu = (student_info *)malloc(sizeof(student_info));    
    stu->age = 18;
    student_info *ptr = container_of(&(stu->age), student_info, age);      
    DEBUG_POINT(stu);//printf("stu address:%p\n", stu);
    DEBUG_POINT(ptr);//printf("ptr address:%p\n", ptr);
    DEBUG_COUT(ptr->age);

    system("pause");
    return 0;
}

 

make一下并且测试一下

 

参考分析Linux内核container_of详解(图解)

    /**
     * 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)const typeof( ((type *)0)->member ) *__mptr = (ptr);
定义一个中间变量__mptr,它等于提供给宏的参数ptr,也就是指向某个成员的指针。这个中间变量的命名意义是:
"__"代表内部使用,内核编程中常常这么做;
“m”代表middle。
 
(2)(type *)( (char *)__mptr - offsetof(type,member) );
这行代码的作用是通过中间变量__mptr(指向某个成员的指针)减去这个成员在容器(结构体)中的偏移来得到指向容器(结构体)的指针。
这里注意偏移的获取offsetof宏的实现
 
红色代表输出,蓝色代表输入,黑色代表中间变量

转载于:https://www.cnblogs.com/libra13179/p/9183650.html

<think>好的,用户想了解container_of宏的使用示例,特别是在C语言内核编程中的应用。我需要先回忆一下这个宏的作用。container_of宏在Linux内核中非常常见,它用于通过结构体成员的指针来获取整个结构体的指针。这对于内核链表等数据结构非常有用。 首先,用户提供的引用中有多个关于container_of宏的定义和解释,比如引用[2]和[3]详细描述了宏的实现。需要确保正确理解这些宏的组成部分,比如offsetof的作用是计算成员在结构体中的偏移量。然后,container_of通过减去这个偏移量来得到结构体的起始地址。 接下来,我需要构建一个使用示例。用户可能需要一个具体的代码例子,展示如何在实际中应用这个宏。例如,在内核中经常用链表结构,每个节点包含一个struct list_head成员,而container_of可以用于从链表节点找到包含它的结构体实例。 在示例中,可以定义一个包含链表节点的结构体,比如struct my_data,其中有一个list成员。然后创建一个实例,初始化链表节点,并通过container_of宏从list成员的指针获取整个struct my_data的指针。这需要包含正确的头文件,比如linux/kernel.h,但用户可能需要注意内核编程的环境。 同时,用户可能想知道宏的参数含义,比如ptr是结构体成员的指针,type是结构体类型,member是成员的名字。需要详细解释每个参数的作用,并确保示例代码中的参数传递正确。 另外,需要注意在内核编程中,可能需要使用特定的宏定义,比如引用[5]中的offsetof定义,或者内核已经提供的实现。用户的问题可能涉及如何正确引用这些宏,是否需要自行定义还是内核已经包含。 最后,生成的相关问题需要围绕container_of宏的应用场景、实现原理以及可能的问题,比如安全性或偏移计算是否正确。这有助于用户进一步理解和应用该宏。</think>### container_of使用示例 `container_of` 宏在 Linux 内核编程中广泛用于**通过结构体成员指针反向获取整个结构体的指针**,尤其在链表操作中十分常见。 #### 示例代码 ```c #include <linux/kernel.h> #include <linux/types.h> // 定义包含链表节点的数据结构 struct my_data { int value; struct list_head list; // 链表成员 char name[20]; }; // 使用示例 void demo_container_of(void) { struct my_data data = { .value = 42, .name = "test" }; // 已知 list 成员地址,反向获取其父结构体 my_data 的指针 struct list_head *ptr = &data.list; struct my_data *parent = container_of(ptr, struct my_data, list); printk("Value: %d, Name: %s\n", parent->value, parent->name); } ``` #### 参数解析 - `ptr`: 结构体成员的指针(示例中的 `&data.list`) - `type`: 目标结构体类型(示例中的 `struct my_data`) - `member`: 成员在结构体中的名称(示例中的 `list`) #### 实现原理 1. **偏移计算**:通过 `offsetof` 宏计算成员在结构体中的偏移量,例如: $$ \text{offset} = \&((\text{struct my_data} *)0)->list $$ 2. **地址转换**:将成员指针转换为字符指针(确保按字节计算),减去偏移量后得到结构体起始地址: $$ \text{parent} = (\text{struct my_data} *)((char *)ptr - \text{offset}) $$[^2][^5] #### 应用场景 - 内核链表遍历时获取宿主结构体(如进程控制块、设备驱动数据结构)[^4] - 实现面向对象风格的数据封装 - 减少冗余指针存储,优化内存使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值