《C语言笔记:offsetof宏和container_of宏》
一,offsetof宏
1,作用:计算结构体中某个元素与结构体首地址的偏移量。
2,原理:虚拟一个0地址处的结构体类型变量type,然后用type.member的方式来访问那个member元素,继而得到member相对于整个变量首地址的偏移量。
3,自己实现:offsetof(type,member) ( (unsigned long) &((type *)0)->member )
4,分布分析:(type *)0 将地址0强制转换为一个结构体类型变量,((type *)0)->member 指向结构体变量的成员,&((type *)0)->member 得到这个成员变量的地址,这个地址是从0地址开始的,故而便是这个成员变量相对于结构体首地址的偏移量。
二,container_of宏
1,作用:知道一个结构体中某个成员变量的指针,来反推这个结构体的指针。使得可以从一个成员变量的指针得到整个结构体的指针,继而得到结构体中其他元素的指针。
2,typeof关键字的作用是:typeof(a)由变量a得到a的类型,由变量名得到变量的数据类型。
3,实现:
#define container_of(ptr,type,member) ({ \
const typeof(((type *)0)->member) *mptr = (ptr);\
(type *)((unsigned long)mptr - offsetof(type, member));\
})
4,原理:先用typeof得到member元素的类型,然后定义成一个这个类型的指针,然后用这个指针减去该元素相对于整个结构体的偏移量(用offsetof宏得到),减去之后得到的就是整个结构体变量的首地址了,再把这个地址强制类型转换为type *就是结构体变量的指针了。
#include<stdio.h> #pragma pack(4) #define offsetof(type,member) ((unsigned long)&((type *)0)->member) #define container_of(ptr,type,member) ({const typeof(((type *)0)->member) *mptr = (ptr);\ (type *)((unsigned long)mptr - offsetof(type, member));}) typedef struct Mystruct1 { // 1字节 4字节 8字节 int a; // 4 4 4 char b; // 1 1+1 1+1 short c; // 2 2 2 }S1; typedef struct Mystruct5{ char a; // 1+3 1+3 S1 s1; // 8 8 double b; // 8 8 int c; // 4 4+8 }S5; int main() { int off; off = offsetof(S1,c); printf(" off = %d \n",off); //6 off = offsetof(S5,b); printf(" off = %d \n",off); //12 S5 s5; S5 *p = NULL; printf(" s5 = %p \n",&s5); //0x7ffc5c373c70 p = container_of(&s5.b,S5,b); printf(" p = %p \n",p); //0x7ffc5c373c70 } #pragma pack()