C语言笔记(结构体与offsetof、container_of之前的关系)

时间:2023-03-09 19:36:50
C语言笔记(结构体与offsetof、container_of之前的关系)

关于结构体学习,需要了解:结构体的定义和使用、内存对齐、结构体指针、得到结构体元素的偏移量(offsetof宏实现)

一、复习结构体的基本定义和使用

 typedef struct mystruct
{
int a;
char b;
double c;
}MyS1; /*
函数功能:演示结构体的定义和使用
*/
void func1(void)
{
//定义时赋值
MyS1 s1 = {
.a =,
.b =,
.c = 1.23,
};
printf("s1.a = %d.\n", s1.a);
printf("s1.b = %d.\n", s1.b);
printf("s1.c = %f.\n", s1.c);
printf("value is change.\n");
// 使用.访问方式赋值
s1.a = ;
s1.b = ;
s1.c = 3.12; printf("s1.a = %d.\n", s1.a);
printf("s1.b = %d.\n", s1.b);
printf("s1.c = %f.\n", s1.c);
}

结果:

C语言笔记(结构体与offsetof、container_of之前的关系)

分析:主要是复习一下结构体的定义和使用。

二、结构体指针的使用

 typedef struct mystruct
{
int a;
char b;
double c;
}MyS1;
/*
函数功能:演示结构体指针的使用
*/
void func2(MyS1 *s_temp)
{
s_temp->a = ;
s_temp->b = ;
s_temp->c = 56.123;
printf("s_temp->a = %d.\n", s_temp->a);
printf("s_temp->a = %d.\n", s_temp->b);
printf("s_temp->a = %f.\n", s_temp->c);
}
int main(void)
{
MyS1 s1;
MyS1 *ps1 = &s1;
func2(ps1);
return ;
}

结果:

C语言笔记(结构体与offsetof、container_of之前的关系)

三、offsetof宏详解

先看看代码,是如何使用offsetof的

 #define offsetof(TYPE, MEMBER)  ((int) &((TYPE *)0)->MEMBER)

 struct mystruct
{
int a;
char b;
double c;
};
int adr_a = offsetof(struct mystruct, b); // adr_a = 4

offsetof宏的分析: #define offsetof(TYPE, MEMBER)  ((int) &((TYPE *)0)->MEMBER)
 1、功能:返回结构体元素的相对结构体首地址的偏移
 2、参数:TYPE是结构体类型,MEMBER是结构体中一个元素的元素名

3、分析:
    (1) (TYPE *)0;  将0转换成结构体指针;
    (2) ((TYPE *)0)->MEMBER; 使用指针方式访问结构体中元素
    (3) &(((TYPE *)0)->MEMBER);  取结构体中元素的地址
    (4) (int) &(((TYPE *)0)->MEMBER); 转换成int型返回

四、container_of宏详解

先看代码

 #define container_of(ptr, type, member) ({  \
const typeof(((type *))->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member));}) typedef struct mystruct
{
int a;
char b;
double c;
}MyS1;
struct mystruct s1;
MyS1 *ps = NULL;
double *p = &s1.c;
printf("&s1 = %p.\n" ,&s1); ps = container_of(p, MyS1, c);
printf("ps = %p.\n" ,ps);

结果:
C语言笔记(结构体与offsetof、container_of之前的关系)

分析:根据&s1.c的地址得到整个结构体的首地址

详解:

#define container_of(ptr, type, member) ({  \
   const typeof(((type *)0)->member) * __mptr = (ptr); \
   (type *)((char *)__mptr - offsetof(type, member));})

 1、功能:返回整个结构体变量的指针
 2、参数:
ptr是指向结构体中一个元素的指针;type是结构体类型;member是结构体中一个元素的元素名

3、分析:
    (1) typeof(((type *)0)->member); 获取结构体中一个元素的类型;s1.c 的类型是double
    (2) const typeof(((type *)0)->member) * __mptr = (ptr); 
        就可以理解为:
        const double * __mptr = (ptr);//__mptr指向ptr处
    (3) (char *)__mptr - offsetof(type, member); // 结构体其中一个元素的地址 - 该元素相对结构体首地址的偏移
    (4) (type *)((char *)__mptr - offsetof(type, member)); // 转换成该结构体类型的指针返回

-----------------------------------------------------------------------------------------------------------------------------------

注:以上程序是参考“朱老师物联网视频”中的代码,特此申明!

----------------------------------------------------------------------------------------------------------------------------