offsetof
定义
//include/linux/stddef.h
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
目的
获得结构体(TYPE)的变量成员(MEMBER)在此结构体中的偏移量
用法
#include <stdio.h>
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
typedef struct test {
int a;
int b;
int c;
int d;
} test_t;
int main(int argc, char const *argv[])
{
int a_offset = offsetof(test_t, a);
int b_offset = offsetof(test_t, b);
int c_offset = offsetof(test_t, c);
int d_offset = offsetof(test_t, d);
printf("a: %d, b: %d, c: %d, d: %d\n", a_offset, b_offset, c_offset, d_offset);
return 0;
}
打印结果:
a: 0, b: 4, c: 8, d: 12
container_of
定义
#define BUILD_BUG_ON_MSG(cond, msg) (0) /* 无意义 */
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) /* 判断类型是否一致 */
//include/linux/kernel.h
#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))); })
目的
根据结构体(type)变量中的成员变量(member)的指针(ptr)来获取指向整个结构体变量的指针
用法
#include <stdio.h>
#define BUILD_BUG_ON_MSG(cond, msg) (0)
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#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))); })
typedef struct test {
int a;
int b;
int c;
int d;
} test_t;
int main(int argc, char const *argv[])
{
test_t t1;
test_t *t2;
t1.a = 1;
t1.b = 2;
t1.c = 3;
t1.d = 4;
t2 = container_of(&t1.a, test_t, a);
printf("t2->a: %d, t2->b: %d, t2->c: %d, t2->d: %d\n", t2->a, t2->b, t2->c, t2->d);
return 0;
}
打印结果:
t2->a: 1, t2->b: 2, t2->c: 3, t2->d: 4
应用
利用container_of构建一个结构体指针变量,并且将第一个参数的值赋值给结构体中对应的成员。
#include <stdio.h>
#define BUILD_BUG_ON_MSG(cond, msg) (0)
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#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))); })
typedef struct test {
int a;
int b;
int c;
int d;
} test_t;
int main(int argc, char const *argv[]) {
int value = 100;
test_t* t1 = container_of(&value, test_t, a);
printf("t1->a: %d\n", t1->a);
test_t* t2 = container_of(&value, test_t, d);
printf("t2->d: %d\n", t2->d);
return 0;
}
打印结果:
t1->a: 100
t2->d: 99
释义
假设代码中value的地址是固定的,固定为0x0010
typedef struct test {
int a;
int b;
int c;
int d;
} test_t;
int main(int argc, char const *argv[]) {
int value = 100;
printf("addr value: %p\n", &value); /* 0x0002 */
size_t a_offset = offsetof(test_t, a);
size_t b_offset = offsetof(test_t, b);
size_t c_offset = offsetof(test_t, c);
size_t d_offset = offsetof(test_t, d);
printf("a_offset: %ld\n", a_offset); /* 0 */
printf("b_offset: %ld\n", b_offset); /* 4 */
printf("c_offset: %ld\n", c_offset); /* 8 */
printf("d_offset: %ld\n", d_offset); /* 12 */
/* 1. 0x0010 - 0 = 0x0010
2. 所以t的地址为 0x0010
3. t->a的地址和t的地址是一致的,所以t->a的地址是 0x0010
4. 0x0010 的地址中存放的数据为value = 100, 所以t->a的值为100
*/
test_t* t = container_of(&value, test_t, a);
/* 1. 0x0010 - 4 = 0x000C
2. 所以t2的地址为 0x000C
3. t2->b的地址是t2的地址偏移4,所以t2->b的地址是 0x0010
4. 0x0010 的地址中存放的数据为value = 100, 所以t2->b的值为100
*/
test_t* t2 = container_of(&value, test_t, b);
return 0;
}