offsetof用于计算TYPE结构体中MEMBER成员的偏移位置。

#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

TYPE:结构体类型

MEMBER:结构体中的某一成员

分析:

1)(TYPE*)0:0被强制转换了,转换成了一个TYPE类型的结构体的指针

2)通过箭头操作,去访问MEMBER成员。问,在0地址处有个TYPE类型的结构体吗?答案肯定是没有的,因为0地址处是留给操作系统使用的。所以在0地址处绝对没有我们自定义的一个TYPE结构体变量。没有的话,这样写(TYPE *)0)->MEMBER,会不会引发程序的崩溃。现在就来讨论这个问题,要想弄明白这个问题,首先要了解编译器做了什么事情。

编译器做了什么?

编译器清楚地知道结构体成员变量的偏移位置;

通过结构体变量首地址与偏移量定位成员变量。

例如:

struct ST

{

  int i ;    //0

  int j;    //4

  char c; //8

}

struct ST s = {0};

struct ST *pst = &s;

int *pi = &(pst->i);  //(unsigned int )&s + 0  就是成员i的地址

int *pj = &(pst->j); //(unsigned int)&s + 4   就是成员j的地址

char *pc =&(pst->c) //(unsigned int)&s +8  就是成员c的地址

从上面可以看出,编译器根本没有真正访问pst所指向的地址中的内容,没有做任何的访问的工作。可以通过下面的成员进行验证:

如果我直接给它传一个空指针,程序会不会崩溃呢,看下面的代码:

从上面可以看出,程序不仅没有崩溃,反而把我们想要的结果打印出来,我们想要的结果就是结构体中的成员变量距离结构体首地址的偏移量。

利用offsetof这个结构体会不会实现同样的效果,继续看代码:

利用offsetof这个宏,成功的计算出了结构体中成员变量的偏移量。

总结:(TYPE *)0)->MEMBER  这个地方不会真正的去访问0地址处的内容,仅仅是编译器做了一个加法而已。用0+MEMBER在结构体中的偏移量,最后计算出一个地址。在此处该地址与MEMBER在结构体中的偏移量相等。

剖析linux内核中的宏-----------offsetof的更多相关文章

  1. 剖析linux内核中的宏---------container_of

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

  2. linux内核中的宏ffs(x)

    linux内核中ffs(x)宏是平台相关的宏,在arm平台,该宏定义在 arch/arm/include/asm/bitops.h #define ffs(x) ({ unsigned long __ ...

  3. KSM剖析——Linux 内核中的内存去耦合

    简介: 作为一个系统管理程序(hypervisor),Linux® 有几个创新,2.6.32 内核中一个有趣的变化是 KSM(Kernel Samepage Merging)  允许这个系统管理程序通 ...

  4. Linux内核中container_of宏的详细解释

    上一节拒绝造轮子!如何移植并使用Linux内核的通用链表(附完整代码实现)我们在分析Linux内核链表的时候注意到内核在求解结构体偏移的时候巧妙的使用了container_of宏定义,今天我们来详细剖 ...

  5. Linux内核中的宏:__init and __exit

    ZZ FROM: http://blog.csdn.net/musein/article/details/742609 ======================================== ...

  6. (十)Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  7. Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  8. Linux内核中的常用宏container_of其实很简单【转】

    转自:http://blog.csdn.net/npy_lp/article/details/7010752 开发平台:Ubuntu11.04 编 译器:gcc version 4.5.2 (Ubun ...

  9. Linux内核中的fastcall和asmlinkage宏

    代码中看见:#define _fastcall 所以了解下fastcall -------------------------------------------------------------- ...

随机推荐

  1. MySQL学习笔记2——DML

    DML(数据操作语言,它是对表记录的操作(增,删,改)!) 1.插入数据 *INSERT INTO 表名(列名1,列名2,...) VALUES(列值1,列值2,...); >在表名后给出要插入 ...

  2. 《京东到家订单中心 Elasticsearch 演进历程》----阅读

    上篇通过阅读文章对京东到家的架构分析有了初步了解,这次对文章(https://mp.weixin.qq.com/s?__biz=MzU1MzE2NzIzMg==&mid=2247486889& ...

  3. Python网络编程基础 ❷ 基于upd的socket服务 TCP黏包现象

    TCP的长连接 基于upd的socket服务 TCP黏包现象

  4. SpringCloud微服务常见组件理解

    概述 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大多数讲解还停留在对Spring Cloud功能使用的层面,其底层的很多原理,很多人可能并不知晓 ...

  5. SVN版本更新自动通知提醒

    当其他用户提交后,如何提示我及时更新代码或版本? 一般情况下,代码的更新时间节点在每天工作开始或有重大功能提交时,所以,不是所有人都对此功能有需求,最好的方式是使用客户端"SVN项目监视器& ...

  6. Unreal Engine 4 系列教程 Part 10:制作简单FPS游戏

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  7. 《一起学netty》

    o文章摘自 netty 官网(netty.io)   netty 是一个异步的,事件驱动的网络应用通信框架,可以让我们快速编写可靠,高性能,高可扩展的服务端和客户端   样例一:discard ser ...

  8. CentOS 7下KVM挂载物理硬盘/硬盘直通

    使用如下的XML配置 <disk type='block' device='disk'> <driver name='qemu' type='raw'/> <source ...

  9. F#周报2019年第23期

    新闻 支持社区的WF与WCF开源项目 视频及幻灯片 F# MonoGame平台游戏系列:摄像头 Xamarin.Forms的F#与Fabulous ML.NET端到端之二:构建Web API 使用F# ...

  10. vue 上传进度显示

    参考资料: https://ask.csdn.net/questions/767017 https://www.cnblogs.com/best-fyx/p/11363506.html 我使用的是el ...