结构体中元素的偏移地址与首地址
1、offsetof()
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE )0)->MEMBER)
它是#include <stddef.h>中的一个宏
目的是:获取一个结构体成员在结构里面的偏移,结构体首地址 = 成员地址- 成员偏移
0指针的使用
#include<stdio.h>
struct test
{
char i ;
int j;
char k;
};
int main()
{
struct test temp;
printf("&temp = %p\n",&temp);
printf("&temp.k = %p\n",&temp.k);
printf("&((struct test *)0)->k = %d\n",((int)&((struct test *)0)->k));
printf("sizeof(temp) = %d\n", sizeof(temp));
return 0
}
&temp = 0061FF14
&temp.k = 0061FF1C
&((struct test *)0)->k = 8
sizeof(temp) = 12
1、通过自定义结构体的三个变量:i, j, k可得,因为有字节对齐的要求,所以该结构的大小为4 bytes * 3 = 12 bytes,而 &(( struct test *) 0)->k的作用就是求k到结构体temp起始地址的字节数大小(size)。
2、在这里0被强制转化为struct test *型, 它的作用就是作为指向该结构体起始地址的指针, 而&((struct test *)0)->k 的作用便是求k到该起始指针的字节数。。。其实是求相对地址,起始地址为0,则&k的值便是size大小(注:打印时因为需要整型,所以有个int强转)所以我们便可以求我们需要的 size 了 。
2、container_of()
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
第二行:const typeof( ((type *)0)->member ) *__mptr = (ptr);
目的:当开发者使用时输入的参数有问题:ptr与member类型不匹配,编译时便会有warnning, (防止出错有不知道错误在哪里),它的作用是获取member的类型仅此而已。
container_of ( ptr, type, member ) 函数的实现包括两部分:
- 判断ptr 与 member 是否为同一类型
- 计算size大小,结构体的起始地址 = (type *)((char *)ptr - size) (注:强转为该结构体指针)
现在我们知道container_of( )的作用就是通过一个结构变量中一个成员的地址找到这个结构体变量的首地址。- container_of(ptr, type, member),这里面有ptr, type, member分别代表指针、类型、成员。
#include <stdio.h>
#include <stdlib.h>
#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)) ;})
struct ptr
{
char a ;
short b ;
int c ;
double d ;
};
int main(void)
{
struct ptr Pt ;
struct ptr *pt ;
printf("ptr:%d\n",sizeof(struct ptr));//16
//获取结构体的首地址
printf("ptr:%p\n",&Pt); //0061FF08
Pt.a = 'a';
Pt.b = 2 ;
Pt.c = 4 ;
Pt.d = 12.04 ;
//通过container of获取结构体的首地址
pt = container_of(&Pt.c, struct ptr , c);
printf("pt:%p\n",pt); //0061FF08
printf("a:%c\n",pt->a) ; //'a'
printf("b:%d\n",pt->b) ; //2
printf("c:%d\n",pt->c) ; //4
printf("d:%.2lf\n",pt->d);//12.04
return 0 ;
}
ptr:16
ptr:0061FF08
pt:0061FF08
a:a
b:2
c:4
d:12.04