offsetof 宏: 结构体成员相对结构体的偏移位置
container_of: 根据结构体成员的地址来获取结构体的地址
offsetof 宏
原型:
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
(TYPE *)0 非常巧妙, 告诉编译器有一个指向结构体 TYPE 的指针, 其地址是 0, 然后取该指针的 MEMBER 地址 &((TYPE *)0)->MEMBER, 因为基址是 0, 所以这时获取到的 MEMBER 的地址就是相当于在结构体 TYPE 中的偏移量了.
- Example:
- #include <stdlib.h>
- #include <stdio.h>
- #include <stddef.h>
- struct TYPE{
- int mem;
- int member;
- };
- int main()
- {
- struct TYPE type;
- printf("&type = %p\n", &type);
- printf("&type.member = %p\n", &type.member);
- printf("&((struct type *)0)->member = %lu\n", ((size_t)&((struct TYPE *)0)->member) );
- printf("offsetof(struct TYPE member) = %zd\n", offsetof(struct TYPE, member));
- return 0;
- }
- /*
- result:
- &type = 0x7ffc1104a110
- &type.member = 0x7ffc1104a114
- &((struct type *)0)->member = 4
- offsetof(struct TYPE member) = 4
- */
container_of 宏
原型: linux-4.18.5
- /**
- * 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) ({ \
- 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))); })
网上所见更多是底下这个版本:
- #define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
第一部分: void *__mptr = (void *)(ptr); 或 const typeof( ((type *)0)->member ) *__mptr = (ptr);
两个的差别在于 __mptr 的类型一个是 void * , 一个是 type *.
void * 较为容易理解, 下面来看看 type *:
关于 typeof 关键字其作用是返回变量的类型, 简单理解就是如下, 详细可参见 GCC typeof 在 kernel 中的使用 --C 语言的 "编译时多态" http://deltamaster.is-programmer.com/posts/37253.html
- int a;
- typeof(a) b; // 这等同于 int b;
- typeof(&a) c; // 这等同于 int* c;
因此 const typeof( ((type *)0)->member ) *__mptr = (ptr); 的作用就是通过 typeof 获取结构体成员 member 的类型, 然后定义一个这个类型的指针变量 __mptr 并将其赋值为 ptr.
第二部分:(type *)( (char *)__mptr - offsetof(type,member) ), 通过 offsetof 宏计算出 member 在 type 中的偏移, 然后用 member 的实际地址__mptr 减去偏移, 得到 type 的起始地址. 从上面关于 offsetof 宏的 Example 也可以验证这一点:
&type.member = 0x7ffc1104a114 - &((struct type *)0)->member = 4 = &type = 0x7ffc1104a110
来源: https://www.cnblogs.com/ZhaoxiCheung/p/9610721.html