container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址。

container_of的定义如下: 

#define container_of(ptr, type, member) ({			\
	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
	(type *)( (char *)__mptr - offsetof(type,member) );})
其实它的语法很简单,只是一些指针的灵活应用,它分两步:
第一步,首先定义一个临时的数据类型(通过typeof(((type *)0)->member)获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。
第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。

其中的语法难点就是如何得出成员相对结构体的偏移量。

通过例子说明,如清单1:

#include <stdio.h>

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

struct test_struct {
    int num;
    char ch;
    float fl;
};

int main(void)
{
    printf("offsetof(struct test_struct, num) = %d\n",offsetof(struct test_struct, num));
    printf("offsetof(struct test_struct,  ch) = %d\n",offsetof(struct test_struct, ch));
    printf("offsetof(struct test_struct,  fl) = %d\n",offsetof(struct test_struct, fl)); 
    return 0;
}

例子输出结果: 

offsetof(struct test_struct, num) = 0
offsetof(struct test_struct,  ch) = 4
offsetof(struct test_struct,  fl) = 8

其中代码难以理解的地方就是它灵活地运用了0地址。如果觉得&((struct test_struct*)0)->ch这样的代码不好理解,那么我们可以假设在0地址分配了一个结构体变量struct test_struct a,然后定义结构体指针变量p并指向a(struct test_struct *p = &a),如此我们就可以通过&p->ch获得成员ch的地址。由于a的首地址为0x0,所以成员ch的首地址为0x4。


最后通过强制类型转换(size_t)把一个地址值转换为一个整数。
分析完container_of的定义,接下来举两个例子来体会一下它的使用方法。

正确的例子,如清单2:

#include <stdio.h>

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

/* include/linux/kernel.h:
 * 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) );})

struct student {
	char name[32];
	int age;
	double score;
};

int main(void)
{
	struct student *temp_jack;
        struct student jack = {"jack", 18, 89.4};
	int *page = &(jack.age); 
	
	temp_jack = container_of(page, struct student, age);
	
	printf("jack's name is %s\n",temp_jack->name);
	printf("jack's age is %d\n",temp_jack->age);
	printf("jack's score is %.2f\n",temp_jack->score);
	
    return 0;
}

例子输出结果:

jack's name is jack
jack's age is 18
jack's score is 89.40

本文主要内容转自:点击打开链接

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐