linux 驱动程序中 container_of宏
该宏利用结构体中元素的指针获取结构体指针
内核中定义如下:
#define container_of(ptr, type, member) ({
void *__mptr = (void *)(ptr);
BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \
!__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
ptr : 表示所指向结构体成员变量的地址
type :表示结构体的类型定义
member : 表示结构体成员的成员名
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
//
计算出结构体成员变量相对于结构体头部偏移, 这个是关键
&((TYPE *)0)->MEMBER:这一个表达式将0地址强制转换成TYPE类型,然后访问member成员,用&获取member成员地址
不是说0地址是非法地址么,为什么这里可以用???
0地址是非法地址没错,但是仅仅是限于不能进行访问操作
ps: 指针的类型 和 指针指向数据的类型区别?
指针本身的类型是int型
指针指向数据的类型则有多种,常见的int,char等等
举例:
int *ptr;
ptr++; //ptr==0x1000,ptr++是将指针的值+4(32位),ptr值为0x1004,
char *ptr;
ptr++; //ptr==0x1000, ptr++就是+1, ptr值为0x1001
int *ptr;
((char)prt)++ //ptr==0x1000, ptr++就是+1, ptr值为0x1001
示例:
#include <stdio.h>
/* 找到指定的成员在定义的结构中的偏移的位置 */
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/* 根据结构体成员的地址,以及结构体成员在结构体中的偏移值计算出结构体变量的地址
* ptr : 结构体成员变量的地址
* type : 结构体的类型定义
* member : 结构体中该成员的定义名称
*/
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
/* 定义一个学生的结构体 */
struct student{
int age; // 年龄字段
int gender; // 性别字段
char *name; // 名字字段
};
/* 程序的入口函数 */
int main(int argc, char *argv[])
{
struct student A;
struct student *pA;
/* 初始化结构体A */
A.age = 20;
A.gender = 1;
A.name = "ChenxiaoPang";
/* 打印结构体A的相关信息 */
printf("A address is %p\n", &A);
printf("A.age = %d\n", A.age);
printf("A.gender = %d\n", A.gender);
printf("A.name = %s\n", A.name);
/* 通过结构体变量A的gender成员的地址找到结构体A的地址 */
pA = container_of(&A.gender, struct student, gender);
/* 打印相关信息 */
printf("pA is %p\n", pA);
printf("pA->age = %d\n", pA->age);
printf("pA->gender = %d\n", pA->gender);
printf("pA->name = %s\n", pA->name);
return 0;
}
上述两种方法打印结果相同