container_of 根据成员变量获得包含其的对象的地址!

写在前面

本系列文章的灵感出处均是各个技术书籍的读后感,详细书籍信息见文章最后的参考文献

CONTAINER_OF

在书中发现一个很有意思的宏,以此可以衍生出来其很多的用法,这个宏可以根据某个成员变量的地址得到包含这个成员变量地址的对象的地址。但是,这个过程很危险,慎用哦!

我们先看这个宏的一个依赖宏:OFFSET_OF,它可以方便的获取此成员变量在这个对象之中的偏移量。

/*
 * @brief OFFSET_OF  获得member在type类型里面的偏移量
 * @param[in] Type: 类型
 * @param[in] MEMBER: 成员变量的名称
 */
#define OFFSET_OF(TYPE, MEMBER) ((size_t)&(static_cast<TYPE *>(0))->MEMBER)

CONTAINER_OF宏可以给定一个成员变量的地址,指定这个成员变量属于哪个对象,指定这个成员变量在对象之中的名称。

/**
 * @brief CONTAINER_OF - 通过三个参数,返回指向数据结构的指针
 * @param[in] ptr:	数据结构中指向某一成员的指针
 * @param[in] type:	数据结构类型
 * @param[in] member:	在数据结构中的成员
 * @note CONTAINER_OF 可以根据某个成员变量的地址得到包含这个成员变量地址的对象的地址。这个过程很危险慎用哦!
 * @return 成员变量的地址
 */
#define CONTAINER_OF(ptr, type, member) ({			\
	const typeof( (static_cast<type*>(0))->member ) *__mptr = (ptr);	\
	(type *)((char*)__mptr - OFFSET_OF(type,member) );})

Demo

int main(){
    foo my_foo;
    foo *p = CONTAINER_OF(&my_foo.a, struct foo, a);
    cout<<p<<endl;
}

输出:

0x7ffc75b6dfc0

其他用法

根据作者在书中所属,这个宏被用于以下几种情形:

  1. 引用计数:对于引用计数结构,可以传递给引用计数一个回调函数,回调函数之中根据这个引用计数对象的地址倒推出包含引用计数的父对象的地址,从而释放资源
//这依赖myref_是对象的公有成员变量
void object_release(struct* ref){
    Object* object = CONTAINER_OF(ref, Object, myref_);
    free(object);
}
  1. 无关类型的双向链表:只要链表的元素之中包含这个node_ 指针,我们在释放的时候,其实就可以便利node_,调用CONTAINER_OF 去获取这个元素的地址,从而释放资源。
class Object{
public:
	some object...
	NodeUnit *node_;
};

参考文献

  1. 《存储技术原理分析》第二章 Linux驱动模型

你可能感兴趣的:(好用的函数,好用的函数)