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

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

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

 1 typedef struct mystruct
 2 {
 3     int a;
 4     char b;
 5     double c;
 6 }MyS1;
 7 
 8 /*
 9     函数功能:演示结构体的定义和使用
10 */
11 void func1(void)
12 {
13     //定义时赋值
14     MyS1 s1 = {
15         .a =1,
16         .b =2,
17         .c = 1.23,
18     };
19     printf("s1.a = %d.
", s1.a);
20     printf("s1.b = %d.
", s1.b);
21     printf("s1.c = %f.
", s1.c);
22     printf("value is change.
");
23     // 使用.访问方式赋值
24     s1.a = 123;
25     s1.b = 4;
26     s1.c = 3.12;
27     
28     printf("s1.a = %d.
", s1.a);
29     printf("s1.b = %d.
", s1.b);
30     printf("s1.c = %f.
", s1.c);
31 }

结果:

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

二、结构体指针的使用

 1 typedef struct mystruct
 2 {
 3     int a;
 4     char b;
 5     double c;
 6 }MyS1;
 7 /*
 8     函数功能:演示结构体指针的使用
 9 */
10 void func2(MyS1 *s_temp)
11 {
12     s_temp->a = 12;
13     s_temp->b = 34;
14     s_temp->c = 56.123;
15     printf("s_temp->a = %d.
", s_temp->a);
16     printf("s_temp->a = %d.
", s_temp->b);
17     printf("s_temp->a = %f.
", s_temp->c);
18 }
19 int main(void)
20 {
21     MyS1 s1;
22     MyS1 *ps1 = &s1;
23     func2(ps1);
24     return 0;
25 }

结果:

三、offsetof宏详解

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

1 #define offsetof(TYPE, MEMBER)  ((int) &((TYPE *)0)->MEMBER)
2 
3 struct mystruct
4 {
5     int a;
6     char b;
7     double c;
8 };
9 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宏详解

先看代码

 1 #define container_of(ptr, type, member) ({  
 2    const typeof(((type *)0)->member) * __mptr = (ptr); 
 3    (type *)((char *)__mptr - offsetof(type, member));})
 4 
 5 typedef struct mystruct
 6 {
 7     int a;
 8     char b;
 9     double c;
10 }MyS1;
11 struct mystruct s1;
12 MyS1 *ps = NULL;
13 double *p = &s1.c;
14 printf("&s1 = %p.
" ,&s1);
15 
16 ps = container_of(p, MyS1, c);
17 printf("ps  = %p.
" ,ps);

结果:

分析:根据&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)); // 转换成该结构体类型的指针返回

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

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

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

原文地址:https://www.cnblogs.com/zou107/p/4950936.html