Chinaunix首页 | 论坛 | 博客
  • 博客访问: 150863
  • 博文数量: 28
  • 博客积分: 1476
  • 博客等级: 上尉
  • 技术积分: 356
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-11 11:39
文章分类
文章存档

2011年(1)

2010年(18)

2009年(9)

我的朋友

分类: 嵌入式

2010-05-27 10:16:34

Linux常用container_of宏从成员变量提取整个结构体的首地针,这个宏的定义如下:

#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

typeof是gcc的一个扩展,用于确定一个变量的类型,有点像C++的RTTI,常用于表达式内的语句,在定义宏时,如果需要临时变量,可以这样做:
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
它可以保证我们定义的变量_a/_b与宏传入的变量a/b类型匹配,而不会产生编译器告警。

因此container_of的第一行就是定义一个与member类型匹配的变量__mptr,赋值后,__mptr为宏参数中的待转换指针,因为只是类型转换,不涉及数据读写,((type*)0)是没有任何副作用的。

第二行用__mptr减去member变量在type中的偏移,这样便可实际访问到ptr相同偏移,也即type的实际首地址了。offsetof有两种定义:

#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

__compiler_offsetof即__builtin_offsetof,__builtin_offsetof可能是gcc內建的支持(见gcc源码c-parser.c),
从后一种实现方式可以明显看到这一技巧,假定一个从0地址开始的结构体,取其成员member的地址正是结构体内的偏移。

如果感觉还不太懂,可以写一个程序,然后预编译,在将两条语句分离出来进行调试慢慢就知道它的原理了,下面贴上我的测试程序

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

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

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
    struct list_head name = LIST_HEAD_INIT(name);

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
//#define ossfetof(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER)


#define container_of(ptr, type, member) ({ \
    const typeof( ((type *)0)->member ) *__mptr = (ptr); \
    (type *)( (char *)__mptr - offsetof(type,member) );})

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

static inline void INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list;
    list->prev = list;
}

static inline void __list_add(struct list_head *new,
                              struct list_head *prev,
                              struct list_head *next)
{
    next->prev = new;
    new->next = next;
    new->prev = prev;
    prev->next = new;
}

static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}

struct stu {
    int n;
    int m;
    struct list_head entry;
};

void test()
{
    struct list_head entry;
    struct list_head entry1;
    struct list_head entry2;
    struct stu student;
    struct stu student1;
    struct list_head *ptr;

    LIST_HEAD(dev_list);

    INIT_LIST_HEAD(&student.entry);
    INIT_LIST_HEAD(&student1.entry);
    student.m = 5;
    student.n = 10;
    student1.m = 8;
    student1.n = 240;

    //INIT_LIST_HEAD(&entry1);
    //INIT_LIST_HEAD(&entry2);

    list_add(&student.entry, &dev_list);
    list_add(&student1.entry, &dev_list);

    const typeof(((struct stu *)0)->entry) *p = dev_list.next;
    struct stu *q;
    q = ((char *)p - ((size_t) & ((struct stu *)0)->entry));

    //for (ptr = dev_list.next; ptr != &dev_list; ptr = ptr->next)

      {
        //ptr = list_entry(ptr, struct stu, entry);
    //}

    //}

    //list_add(&entry1, &dev_list);
    //list_add(&entry2, &dev_list);
}

int main()
{
    test();
    return 0;
}


阅读(1877) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~