首页 > c/c++, linux > c中出现的offsetof宏和container_of宏 解析

c中出现的offsetof宏和container_of宏 解析

2015年12月27日 588 人阅读 发表评论 阅读评论
1、offsetof宏用于求成员变量在结构体中的偏移量
#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE*)0)->MEMBER)
我们来逐步分解这个宏:
((TYPE*)0) 把地址值为0指针转换为TYPE指针
((TYPE*)0)->MEMBER 解指针应用,求起始地址为0的类型为TYPE的成员MEMBER
&((TYPE*)0)->MEMBER 求起始地址为0的类型为TYPE的成员MEMBER的地址
((size_t)&((TYPE*)0)->MEMBER) 把起始地址为0的类型为TYPE的成员MEMBER的地址值类型转换为size_t类型
综上我们可以看到一个很巧妙的地方,就是把值为0的地址转换为TYPE*指针,这样求得的MEMBER的地址就是成员MEMBER在TYPE中的偏移量。

2、container_of宏用于已知一个结构体变量中某一成员变量的地址,反过来求结构体变量的起始地址
#define container_of(ptr, type, member) ({                           \ 
const typeof( ((type *)0)->member ) *__mptr = (ptr);    \ 
(type *)( (char *)__mptr – offsetof(type,member) );})
这个宏展开是一个二分拣表达式,它的值是最后一个分句决定的,也就是说这个宏展开后返回的值类型是type *
我们也逐步来分解这个宏:
const typeof( ((type *)0)->member ) *__mptr = (ptr); 声明一个const的结构体中成员member类型的指针变量__mptr,并使用ptr赋值。
(type *)( (char *)__mptr – offsetof(type,member) ); 把指针__mptr的类型转换为char *,并减去member在type中的偏移量,最后再把这个求得的指针值转换为type *,而这个值就是成员变量(*ptr)对应的结构体type变量的起始地址了。
3、Demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
 
#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) );})
 
struct Test
{
	int a;
	short b;
	char c;
};
 
 
int main()
{
	Test t;
	printf("offsetof(Test, a)=%d\n", offsetof(Test, a));
	printf("offsetof(Test, b)=%d\n", offsetof(Test, b));
	printf("offsetof(Test, c)=%d\n", offsetof(Test, c));
 
	printf("address t=%p, container_of t=%p\n", &t, container_of(&t.a, Test, a));
	printf("address t=%p, container_of t=%p\n", &t, container_of(&t.b, Test, b));
	printf("address t=%p, container_of t=%p\n", &t, container_of(&t.c, Test, c));
 
	return 0;
}
分类: c/c++, linux 标签:
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.