#include <stdio.h>

#define offset_of(type,member) ((int)&(((type *)0)->member))

#define container_of(ptr,type,member) ({\
const typeof(((type*))->member) *__mptr = ptr;\
(type *)((char *)__mptr - offset_of(type,member));\
}) struct mytest{
char i;
int j;
char *k;
};
int main(){
struct mytest temp;
struct mytest *p;
printf("&temp = %p\n",&temp);
printf("&temp.k = %p\n",&temp.k);
printf("&((struct mytest *)0)->k = %d\n",((int)&((struct mytest *))->k));
printf("&temp = %p \n",container_of(&temp.j,struct mytest,j));
printf("&temp = %p \n",container_of(&temp.k,struct mytest,k));
return ;}

(一).分析下宏定义1:

#define offset_of(type,member) ((int)&(((type *)0)->member))

(type * )0 :强制把0地址转化为type *类型

&(((type *)0)->member) :将type类型的member成员的地址取出。这里用法很妙,由于type指针地址是0,故其成员地址都是基地址为0加上偏移地址。

(int)(&(((type *)0)->member)) :将type成员类型地址强制转化为int。

(二).分析下宏定义2:

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

2.1. 分析 const typeof(((type *)0)->member) *__mptr = ptr;

const typeof(((type *)0)->member) :typeof是关键字,获取成员类型。此部分是得到宏传过来的成员类型。

const typeof(((type *)0)->member) *__mptr = ptr :此部分为什么要重新定义__mptr呢?这就是写linux内核工程师的牛逼,严谨之处。如果开发者使                用时输入的参数有问题:ptr与member类型不匹配,编译时便会有warnning, 但是如果去掉改行,那个就没有了,而这个警告恰恰是必须的(防止出错有不              知道错误在哪里)。。。

2.2. 分析(type *)((char *)__mptr - offset_of(type,member));

(char *)__mptr :将成员类型强制转化为char *,如此地址进行加减时以字节为单位

(char *)__mptr - offset_of(type,member) :计算出结构体首地址,此时地址类型为char *

(type *)((char *)__mptr - offset_of(type,member)):将char * 强制转化为(type *)

索引文献:https://blog.csdn.net/s2603898260/article/details/79371024

关于container_of函数分析的更多相关文章

  1. split(),preg_split()与explode()函数分析与介

    split(),preg_split()与explode()函数分析与介 发布时间:2013-06-01 18:32:45   来源:尔玉毕业设计   评论:0 点击:965 split()函数可以实 ...

  2. string函数分析

    string函数分析string函数包含在string.c文件中,经常被C文件使用.1. strcpy函数原型: char* strcpy(char* str1,char* str2);函数功能: 把 ...

  3. start_amboot()函数分析

    一.整体流程 start_amboot()函数是执行完start.S汇编文件后第一个C语言函数,完成的功能自然还是初始化的工作 . 1.全局变量指针r8设定,以及全局变量区清零 2.执行一些类初始化函 ...

  4. uboot的jumptable_init函数分析

    一.函数说明 函数功能:安装系统函数指针 函数位置:common/exports.c 二.函数分析 void jumptable_init (void) { int i; gd->jt = (v ...

  5. Linux-0.11内核源代码分析系列:内存管理get_free_page()函数分析

    Linux-0.11内存管理模块是源码中比較难以理解的部分,如今把笔者个人的理解发表 先发Linux-0.11内核内存管理get_free_page()函数分析 有时间再写其它函数或者文件的:) /* ...

  6. 31.QPainter-rotate()函数分析-文字旋转不倾斜,图片旋转实现等待

    在上章和上上上章: 28.QT-QPainter介绍 30.QT-渐变之QLinearGradient. QConicalGradient.QRadialGradient 学习了QPainter基础绘 ...

  7. 如何验证一个地址可否使用—— MmIsAddressValid函数分析

    又是一篇内核函数分析的博文,我个人觉得Windows的内核是最好的老师,当你想实现一个功能之前可以看看Windows内核是怎么做的,说不定就有灵感呢:) 首先看下官方的注释说明: /*++ Routi ...

  8. STM32F10X固件库函数——串口清状态位函数分析

    STM32F10X固件库函数——串口清状态位函数分析 最近在测试串口热插拔功能的时候,意外发现STM32F10X的串口库函数中,清理串口状态位函数稍稍有点不解.下面是改函数的源码: /******** ...

  9. 常用string函数分析

    string函数分析string函数包含在string.c文件中,经常被C文件使用.1. strcpy函数原型: char* strcpy(char* str1,char* str2);函数功能: 把 ...

随机推荐

  1. JAVA RPC (十) nio服务端解析

    源码地址:https://gitee.com/a1234567891/koalas-rpc 企业生产级百亿日PV高可用可拓展的RPC框架.理论上并发数量接近服务器带宽,客户端采用thrift协议,服务 ...

  2. Servlet页面跳转的两种方式

    一.页面跳转 1. 请求转发: (1) 使用requestDispatcher对象: 转发格式:request.getRequestDispatcher("path").forwa ...

  3. mybatis中foreach参数过多效率很慢的优化

    foreach 后面in 传入的参数有1万条,#和$是有效率区别的,$的效率远高于#,上篇文章做了比较. 但没达到我的理想结果. 1. 更改方式,把foreach 去掉,改成拼装方式, 参数直接拼装成 ...

  4. java经典算法题50道

    原文 JAVA经典算法50题[程序1]   题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?1.程序 ...

  5. python项目生成及导入依赖的第三方库

    requirements.txt用来记录项目所有的依赖包和版本号,只需要一个简单的pip命令就能完成. pip freeze >requirements.txt 然后就可以用 pip insta ...

  6. SQL-W3School-高级:SQL BETWEEN 操作符

    ylbtech-SQL-W3School-高级:SQL BETWEEN 操作符 1.返回顶部 1. BETWEEN 操作符在 WHERE 子句中使用,作用是选取介于两个值之间的数据范围. BETWEE ...

  7. css简单学习属性

      1:内联元素和块级元素 1).块级元素,默认是:内联元素可以变成块级元素,块级元素可以变成内联元素. <!DOCTYPE html> <html lang="en&qu ...

  8. 图解 HTTP 笔记(一)——了解 Web 及网络基础

    本章内容:Web 建立在何种技术之上,HTTP 协议如何诞生并发展? 一.Web 基于 HTTP 通信 Web 使用一种名为 HTTP (HyperText Transfer Protocol,超文本 ...

  9. java引用如果是成员变量则引用本身不保存在栈上的汇编级调试证明

    很久很久没有更新博客了,因为发生太多太多猝不及防的事情,再加上自己本身也特别忙,这里补上一直想发的自己觉得很有意义的一次探索过程. 就是很多java开发人员都曾被误导的一个点——“如果一个变量是引用, ...

  10. Java NIO 学习笔记 缓冲区补充

    1.缓冲区分配 方法   以 ByteBuffer 为例 (1)使用静态方法 ByteBuffer buffer = ByteBuffer.allocate( 500 ); allocate() 方法 ...