container_of分析

协议栈分析过程中遇到的知识点记录。

转自:http://blog.youkuaiyun.com/tigerjibo/article/details/8299589,此处只用于个人收藏总结、学习


1.container_of宏

1> Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址。
2>接口:
container_of(ptr, type, member) 
ptr:表示结构体中member的地址
type:表示结构体类型
member:表示结构体中的成员
通过ptr的地址可以返回结构体的首地址
3> 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的值。
说明:typeof是GNU C对标准C的扩展,它的作用是根据变量获取变量的类型《typeof关键字在linux 内核中很常见》
第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。
offsetof为number在结构体中的偏移量。

2. 举例来说明container_of的使用

1>正确示例:

#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_struct {
           int num;
          char ch;
          float f1;
  };
 int main(void)
  {
          struct test_struct *test_struct;
          struct test_struct init_struct ={12,'a',12.3};
          char *ptr_ch = &init_struct.ch;
          test_struct = container_of(ptr_ch,struct test_struct,ch);
          printf("test_struct->num =%d\n",test_struct->num);
          printf("test_struct->ch =%c\n",test_struct->ch);
          printf("test_struct->ch =%f\n",test_struct->f1);
          return 0;
  }
执行结果:
jibo@jibo-VirtualBox:~/cv_work/work/list/container_of $ ./main
test_struct->num =12
test_struct->ch =a
test_struct->ch =12.300000

container_of宏的作用是从包含在某个结构体中的结构成员获取结构体本身的指针,也就是通过结构体变量中的某个成员的首地址获取结构体的首地址。其实现原理如下: ### 原型定义 ```c #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); }) #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) ``` ### 原理分析 1. **offsetof宏的作用**:`offsetof(TYPE, MEMBER)` 宏用于计算结构体 `TYPE` 中成员 `MEMBER` 相对于结构体起始地址的偏移量。它的实现方式是将 `0` 强制转换为 `TYPE *` 类型的指针,这意味着将地址 `0` 视为结构体的起始地址。然后通过 `->` 操作符访问成员 `MEMBER`,并取其地址。由于结构体起始地址为 `0`,所以该成员的地址值就等于其相对于结构体起始位置的偏移量。最后将其转换为 `size_t` 类型返回 [^1][^4]。 2. **container_of宏的实现**: - 首先,`const typeof(((type *)0)->member) * __mptr = (ptr);` 这一行代码定义了一个临时指针 `__mptr`,其类型与结构体 `type` 中成员 `member` 的类型相同,并将传入的成员指针 `ptr` 赋值给它。这一步主要用于类型检查,确保传入的指针类型与结构体成员类型一致 [^1][^4]。 - 接着,`(type *)((char *)__mptr - offsetof(type, member));` 这一行是核心计算部分。先将 `__mptr` 强制转换为 `char *` 类型,这是因为 `char` 类型的指针在进行指针运算时,每次移动的步长为 `1` 字节。然后用成员指针 `__mptr` 减去成员相对于结构体起始位置的偏移量,得到结构体的起始地址。最后将结果强制转换为 `type *` 类型,即结构体指针类型 [^1][^4]。 ### 简单示例 ```c #include <stdio.h> #include <stddef.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 example { int a; char b; double c; }; int main() { struct example var; // 获取成员 c 的地址 double *c_ptr = &var.c; // 通过 container_of 宏获取结构体的地址 struct example *ptr = container_of(c_ptr, struct example, c); // 验证获取的结构体地址是否正确 if (ptr == &var) { printf("Successfully retrieved the address of the structure!\n"); } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值