资讯详情

C语言结构体中不得不知的技巧-offsetof()与 container_of()的用法

C语言结构中必须知道的技能-offsetof()与 container_of()的用法

引言: 赋予了结构体的使用C 语言面向对象的特征。我们经常在结构中包装一系列变量和函数,以便于这些参数的管理。然而,包装的操作带来了好处,并且很容易隐藏一些内部细节,这使得我们很难理解结构中的细节。 linux 大量使用结构体 offsetof()container_of(),研究发现,他们确实很有用,所以他们写这篇文章作为分享。

功能简介

  1. offsetof() 原型如下:
offsetof(TYPE, MEMBER) /* 1.功能:返回结构成员 MEMBER 的相对结构体 TYPE 首个地址的偏移量。 2、参数:TYPE结构类型,MEMBER是结构中成员的名字。 */ 

2)container_of() 原型如下:

container_of(ptr, type, member) /*  1.功能:通过结构成员的指针获得整个结构本身的指针,即通过局部成员的地址获得整个结构地址。  2、参数:ptr 是指结构中成员变量地址的指针;type结构类型;member它是结构中对应成员变量的名称。  */ 

代码验证

#undef offsetof #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #undef container_of /** * copy from linux * 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) );})  typedef struct custom_struct { 
             int a;/span> 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 %s\r\n", p_test->info.name); } void app_main(void) { 
          printf("init done\r\n"); 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=%d\r\n", adr_a); printf("adr_b=%d\r\n", adr_b); printf("adr_c=%d\r\n", adr_c); printf("adr_d=%d\r\n", adr_d); printf("adr_id=%d\r\n", adr_id); printf("adr_name=%d\r\n", adr_name); (void)memset(&test, 0, offsetof(custom_struct, info.id)); printf("a=%d\r\n", test.a); printf("b=%d\r\n", test.b); printf("c=%c\r\n", test.c); printf("d=%c\r\n", test.d); printf("test's ptr is %p\r\n", &test); custom_struct *p_test = container_of(&test.b, custom_struct, b); printf("test's ptr calculated from the sub is %p\r\n", 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 的值。成功实现从局部获取到整体。真令人开心阿,哈哈。 (代码可以直接复制粘贴进行验证奥~) (码字不易,谢谢点赞或收藏,你的鼓励,我的动力)

标签: adr03arz集成电路ic

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台