31.offsetof宏与container_of宏

来源:互联网 发布:电子产品设计软件 编辑:程序博客网 时间:2024/05/23 22:02

31.1.offsetof宏
(1)作用:用宏来计算结构体中某个元素和结构体首地址的偏移量(其本质是通过编译器来帮我们计算)。
(2)原理:我们虚拟1个type类型结构体变量,然后用type.member的方式来访问某个member元素,继而得到member相对于整个变量首地址的偏移量。
(3)学习思路:第1步先学会用offsetof宏;第2步再去理解这个宏的实现原理(见图1)。


31.2.container_of宏
(1)作用:知道某个结构体中某个元素的指针,反推整个结构体变量的指针,继而得到结构体中其它元素的指针。
(2)typeof关键字:typeof(a)即由变量a得到a的类型,typeof就是由变量名得到变量的数据类型。
(3)原理:先用typeof得到member元素的类型,然后通过该类型定义指向member元素的指针,然后用该指针减去该元素相对于整个结构体变量的偏移量(偏移量用offsetof宏得到)后得到整个结构体变量的首地址,再把该地址强制类型转换为type *即可。
(3)学习思路:第1步先学会用container_of宏;第2步再去理解这个宏的实现原理(见图2)。


31.3.学习指南和要求
(1)基本要求:必须要掌握这两个宏的使用,即知道这两个宏接收什么参数,返回什么值,会用这两个宏来写代码,看见代码中别人用这两个宏能理解什么意思。
(2)升级要求:能理解这两个宏的工作原理,能表述出来,有些面试笔试题会这么要求。
(3)高级要求:能自己写出这两个宏,不要着急,慢慢来。


这里写图片描述


这里写图片描述


31.struct_macro/* * 公司:XXXX * 作者:Rston * 博客:http://blog.csdn.net/rston * GitHub:https://github.com/rston * 项目:offsetof宏与container_of宏 * 功能:演示offsetof宏与container_of宏的使用。 */#include <stdio.h>// offsetof宏:返回MEMBER元素相对于整个TYPE类型结构体首地址的偏移量// 参数:TYPE为某个结构体类型,MEMBER为TYPE类型结构体中的某个元素#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)// container_of宏:返回整个结构体变量的指针// 参数:ptr为指向结构体中member元素的指针,type为某个结构体类型,member为该结构体中的某个元素#define container_of(ptr, type, member) ({          \    const typeof(((type *)0)->member) * __mptr = (ptr); \    (type *)((char *)__mptr - offsetof(type, member)); })struct mystruct{    char a;         // 偏移量0    int b;          // 偏移量4    short c;        // 偏移量8 };int main(int argc, char **argv){    // 手动计算偏移量,然后通过指针方式访问结构体元素    struct mystruct s1 =     {        .a = 'c',        .b = 20,        .c = 8,    };    char *p1 = (char *)&s1;    int *p2 = (int *)((char *)&s1 + 4);    short int *p3 = (short int *)((char *)&s1 + 8);    // *p1 = c. *p2 = 20. *p3 = 8.    printf("*p1 = %c. *p2 = %d. *p3 = %d.\n", *p1, *p2, *p3);    // 使用offsetof宏    // offsetof(struct mystruct, a) = 0.    // (char *)&(s1.a) - (char *)&s1 = 0.    printf("offsetof(struct mystruct, a) = %d.\n", offsetof(struct mystruct, a));    printf("(char *)&(s1.a) - (char *)&s1 = %d.\n", (char *)&(s1.a) - (char *)&s1);    // offsetof(struct mystruct, b) = 4.    // (char *)&(s1.b) - (char *)&s1 = 4.    printf("offsetof(struct mystruct, b) = %d.\n", offsetof(struct mystruct, b));    printf("(char *)&(s1.b) - (char *)&s1 = %d.\n", (char *)&(s1.b) - (char *)&s1);    // offsetof(struct mystruct, c) = 8.    // (char *)&(s1.c) - (char *)&s1 = 8.    printf("offsetof(struct mystruct, c) = %d.\n", offsetof(struct mystruct, c));    printf("(char *)&(s1.c) - (char *)&s1 = %d.\n", (char *)&(s1.c) - (char *)&s1);    // 使用container_ofstruct mystruct s2 =     {        .a = 'd',        .b = 30,        .c = 5,    };    // pS = 0xbfcc8350. &s2 = 0xbfcc8350.    struct mystruct *pS = container_of(&(s2.a), struct mystruct, a);    printf("pS = %p. &s2 = %p.\n", pS, &s2);    return 0;}

0 0
原创粉丝点击