container_of学习
2016-07-15 08:16
639 查看
container_of学习
[TOC]
定义
定义1:#define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); \ (type *)((char *)__mptr - ((unsigned long) &((type *)0)->member)); })
定义2:
//获取结构体成员地址偏移
#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
//根据结构成员地址找到结构首地址
#define container_of(ptr, type, member) \ ((type *)(void *)((char *)(ptr) - offsetof(type, member)))
头文件包含:
offsetof宏需要包含stddef.h头文件,container_of宏需要包含linux/kernel.h头文件。
作用:
根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针
用法说明:
获取member的父结构 ptr: 父结构实例member的指针 type: 父结构 member: 父结构成员名
通俗的解释就是:
参数3是参数2这个结构体的一个成员的名字,而不是类型名 ;
参数1是一个指针,它指向参数3这个成员。
定义解析
1
typeof
typeof是GNU C对标准C的扩展,它的作用是根据变量获取变量的类型2。
例如:
int x = 5; typeof(x) y = 6; printf("%d %d\n", x, y);
典型应用:
//定义一个安全的max宏
#define max(a,b) \ ({ typeof (a) _a = (a); \ typeof (b) _b = (b); \ _a > _b ? _a : _b; })
定义1中代码:
const typeof(((type *)0)->member) * __mptr = (ptr);
的作用是首先使用typeof获取结构体域变量member3的类型为 type3,然后定义了一个type3指针类型的临时变量__mptr,并将实际结构体变量中的域变量的指针memp的值赋给临时变量__mptr
(char *)__mptr转换为字节型指针
(type )将字节型的结构体起始指针转换为type 型的结构体起始指针
offsetof
offsetof就是取结构体中的域成员相对于地址0的偏移地址,也就是域成员变量相对于结构体变量首地址的偏移。
代码 | 含义 |
---|---|
( (TYPE *)0 ) | 将零转型为TYPE类型指针; |
( (TYPE *)0 )->MEMBER | 访问结构中的数据成员; |
&( ( (TYPE *)0 )->MEMBER ) | 取出数据成员的地址; |
(size_t)(&(((TYPE*)0)->MEMBER)) | 结果转换类型。 |
实例
实例一(一般用法):struct demo_struct { type1 member1; type2 member2; type3 member3; type4 member4; }; struct demo_struct demo;
已知变量demo中的某一个域成员变量的指针,比如:
type3 *memp = get_member_pointer_from_somewhere();
此时,如果需要获取指向整个结构体变量的指针,如下:
struct demo_struct *demop = container_of(memp, struct demo_struct, member3);
实例二(项目工程中常用):
typedef struct tagDemo { u32 instanceId; void *ctrArray[10]; int *ObjArray[10]; u64 other; }Demo_S;
已知:int **Res,数组ObjArray中索引index
instance = (Demo_S*)container_of(Res, Demo_S, ObjArray[Index]);
有时候用container_of会导致pclint不过,这时候的替代写法如下:
instance = (Demo_S *)(void *)((char *)Res - offsetof(Demo_S, ObjArray) - sizeof(int*)*Index);
offsetof也可以只得到数组首地址,然后再偏移
实验
代码(这里复用了3,然后加入数组的偏移实验,来验证上面的实例)://cont_of.c #include <stdio.h> #include <stdlib.h> #define NAME_STR_LEN 32 #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) );}) typedef struct student_info { int id; char name[NAME_STR_LEN]; int age; }student_info; int main() { size_t off_set = 0; off_set = offsetof(student_info, id); printf("id offset: %u\n",off_set); off_set = offsetof(student_info, name); printf("name offset: %u\n",off_set); off_set = offsetof(student_info, name[10]); printf("name[10] offset: %u\n",off_set); off_set = offsetof(student_info, age); printf("age offset: %u\n",off_set); student_info *stu = (student_info *)malloc(sizeof(student_info)); student_info *ptr = container_of(&(stu->age), student_info, age); student_info *ptr1 = container_of(&(stu->name[10]), student_info, name[10]); printf("stu address:%p\n", stu); printf("ptr address:%p\n", ptr); printf("ptr1 address:%p\n", ptr1); return 0; }
编译运行:
gcc cont_of.c -o cc ./cc
运行结果如下:
id offset: 0 name offset: 4 name[10] offset: 14 age offset: 36 stu address:0x602010 ptr address:0x602010 ptr1 address:0x602010
http://gcc.gnu.org/onlinedocs/gcc/Typeof.html ↩
http://www.cnblogs.com/Anker/p/3472271.html ↩
http://radek.io/2012/11/10/magical-container_of-macro/ ↩
相关文章推荐
- 学习 Linux 是我们的爱情语言
- 责任链模式(Chain of Responsibility)的标准版
- 基础命令学习总结
- Prototype 学习 工具函数学习($方法)
- Validation of viewstate MAC failed.的解决方法
- PERL脚本 学习笔记
- 学习 WSH 的理由小结
- Prototype 学习 工具函数学习($A方法)
- jQuery 学习 几种常用方法
- for循环中删除map中的元素valgrind检测提示error:Invalid read of size 8
- awk简介与学习笔记收集第1/3页
- php学习 字符串课件
- 供参考的 php 学习提高路线分享
- PHP的FTP学习(二)
- PHP学习之PHP表达式
- php学习 面向对象 课件第1/2页
- 学习使用PHP数组
- PHP学习一(基础)第1/2页
- 快速入门的一些C\C++书籍
- bootstrap学习笔记之初识bootstrap