引言: 结构体的使用赋予了C 语言“面向对象”的特性。我们经常将一系列变量、函数封装在一个结构体中,来方便管理这些参数。但是“封装”这种操作,带来好处的同时容易隐藏掉一些内部的细节,使得我们想了解结构体中的细节变得麻烦。最近看 linux 中关于结构体的使用中大量使用了 offsetof()与 container_of(),研究发现,他们的确很有用,遂作此文,作为分享。
功能简介- offsetof() 原型如下:
offsetof(TYPE, MEMBER)
2)container_of() 原型如下:
container_of(ptr, type, member)代码验证
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#undef container_of
#define container_of(ptr, type, member) ({
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
typedef struct custom_struct {
int a;
size_t b;
char c;
char d;
struct {
uint8_t id;
char *name;
} info;
}custom_struct;
void printf_name(size_t *p_b)
{
custom_struct *p_test = container_of(p_b, custom_struct, b);
printf("name is %srn", p_test->info.name);
}
void app_main(void)
{
printf("init donern");
custom_struct test = {1,2,'3','4',
.info = {
.name="custom",
}};
int adr_a = offsetof(custom_struct, a);
int adr_b = offsetof(custom_struct, b);
int adr_c = offsetof(custom_struct, c);
int adr_d = offsetof(custom_struct, d);
int adr_id = offsetof(custom_struct, info.id);
int adr_name = offsetof(custom_struct, info.name);
printf("adr_a=%drn", adr_a);
printf("adr_b=%drn", adr_b);
printf("adr_c=%drn", adr_c);
printf("adr_d=%drn", adr_d);
printf("adr_id=%drn", adr_id);
printf("adr_name=%drn", adr_name);
(void)memset(&test, 0, offsetof(custom_struct, info.id));
printf("a=%drn", test.a);
printf("b=%drn", test.b);
printf("c=%crn", test.c);
printf("d=%crn", test.d);
printf("test's ptr is %prn", &test);
custom_struct *p_test = container_of(&test.b, custom_struct, b);
printf("test's ptr calculated from the sub is %prn", p_test);
printf_name(&test.b);
}
输出结果:
init done adr_a=0 adr_b=4 adr_c=8 adr_d=9 adr_id=12 adr_name=16 a=0 b=0 c= d= test's ptr is 0x3ffb5c80 test's ptr calculated from the sub is 0x3ffb5c80 name is custom
结果分析:
1)offsetof() 获取了成员相对于整个结构体的偏移地址。程序中使用 (void)memset(&test, 0, offsetof(custom_struct, info.id)); 语句清除了结构体中部分变量的值。
2)结构体变量 test 的地址与 container_of() 计算获取的该结构体 变量的地址一致。更进一步地,在 printf_name() 内成功地通过结构体变量 test 的成员变量 b,访问到了 结构体变量 test 的成员 name 的值。成功实现从局部获取到整体。真令人开心阿,哈哈。
(代码可以直接复制粘贴进行验证奥~)
(码字不易,谢谢点赞或收藏,你的鼓励,我的动力)



