container_of()宏解析

来源:互联网 发布:淘宝能卖什么东西 编辑:程序博客网 时间:2024/05/18 00:20

        在内核中很多地方都会使用到宏container_of()。

        都知道宏container_of()的作用是:根据结构体中一个域成员变量的指针获取指向整个结构体的指针、现在来分析这个宏是如何实现的;

        内核中container_of()代码如下:

/** * container_of - cast a member of a structure out to the containing structure * @ptr:    the pointer to the member. * @type:   the type of the container struct this is embedded in. * @member: the name of the member within the struct. */#define container_of(ptr, type, member) ({          \const typeof(((type *)0)->member)*__mptr = (ptr);    \     (type *)((char *)__mptr - offsetof(type, member)); })

        内核中offsetof()代码如下:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
一、理论解析

       先来说说offsetof()宏;

       1. (type *)0:将0转化为TYPE型指针;

       2. (TYPE *)0)->MEMBER:表示访问TYPE型指针0指向结构体的成员变量MEMBER;

       3. &((TYPE *)0)->MEMBER):表示取成员变量MEMBER的地址;

       4. ((size_t) :类型转化

       巧妙之处在于:将0转换成(TYPE*),然后结构体以内存空间首地址0作为起始地址,则成员地址就成为偏移地址。

       再来说说container_of()宏;

       1.  typeof(((type *)0)->member)的作用是获取成员member的结构类型;

        2. typeof(((type *)0)->member)*__mptr == (ptr);表示定义临时变量__mptr,将指针ptr赋值给__mptr;

        3. (type *)( (char *)__mptr - offsetof(type,member) )在(type *)作用下进行将字节型的结构体起始指针转换为type *型的结构体起始指针;

二、案例解析:

        以类型struct example_st为例:

struct example_st{type_fst mem1;type_sec mem2;type_thd mem3;type_fth mem4;};

         进行地址标记:


        container_of(sec, struct example_st, mem2))代入宏

container_of(sec, struct example_st, mem2) ({          \const typeof(((struct example_st *)0)->mem2)*__mptr = (sec);    \        (struct example_st *)((char *)__mptr - offsetof(struct example_st, mem2)); })
        第三行offsetof是计算mem2在结构体struct example_st,中偏移量,等于0x0008;
        第二行可知__mptr = 0xa018;

        第三行计算结果是:0xa018 - 0x0008 = 0xa0010;

三、程序实例

list.h

/********************************************** * Author: lewiyon@hotmail.com * File name: list.h * Description: define some macroes * Date: 2011-12-29 *********************************************/#ifndef __LIST_H#define __LIST_H//typedef unsigned long size_t;#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)#define container_of(ptr, type, member) ({          \        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \        (type *)( (char *)__mptr - offsetof(type,member) );})#endif

test.c

/********************************************** * Author: lewiyon@hotmail.com * File name: test.h * Description: test the macroes in the core.h  * Date: 2011-12-29 *********************************************/#include <malloc.h>#include "list.h"struct student{    char *name;    char sex;    unsigned long id;    int age;    int money;};static struct student *id_stu(unsigned long *id_no){    return (container_of(id_no, struct student, id));}int main(int argc, char *argv[]){    unsigned long offset;    struct student *stu, *stu_tst;    stu_tst = NULL;    stu = (struct student *)malloc(sizeof(struct student));    stu->name = "lewiyon";     stu->sex = 'M';     stu->id = 2004035000;     stu->age = 26;     stu->money =0;    printf("-------------------------------\n");    printf("stu         = %p\n", stu);    printf("&stu->name  = %p\n", &stu->name);    printf("&stu->sex   = %p\n", &stu->sex);    printf("&stu->id    = %p\n", &stu->id);    printf("&stu->age   = %p\n", &stu->age);    printf("&stu->money = %p\n", &stu->money);    printf("stu->name   = %s\n", stu->name);    printf("-------------------------------\n");        stu_tst = id_stu(&stu->id);    offset = offsetof(struct student, id);    printf("offset          = %p\n", offset);    printf("stu_tst         = %p\n", stu_tst);    printf("&stu_tst->name  = %p\n", &stu_tst->name);    printf("&stu_tst->sex   = %p\n", &stu_tst->sex);    printf("&stu_tst->id    = %p\n", &stu_tst->id);    printf("&stu_tst->age   = %p\n", &stu_tst->age);    printf("&stu_tst->money = %p\n", &stu_tst->money);    printf("stu_tst->name   = %s\n", stu_tst->name);    return 0;}

原创粉丝点击