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. selenium定位元素的八种方法

    web driver提供了八种元素定位的方法: id, name, class name, tag name, link text, partial link text, xpath, css sel ...

  2. Velocity与Jsp、Freemarker的对比

    在java领域,表现层技术主要有三种:jsp.freemarker.velocity.jsp是大家最熟悉的技术 优点: 1.功能强大,可以写java代码 2.支持jsp标签(jsp tag) 3.支持 ...

  3. 工具资源系列之给 windows 虚拟机装个 ubuntu

    前面我们已经介绍了如何在 Windows 宿主机安装 VMware 虚拟机,这节我们将利用安装好的 VMware 软件安装 Ubuntu 系统. 前情回顾 虚拟机为我们在 Windows 宿主机体验别 ...

  4. Python process (进程)

    进程 (process) 进程是对各种资源管理的集合,包含对各种资源的调用.内存的管理.网络接口的调用 进程要操作 CPU 必须先启动一个线程,启动一个进程的时候会自动创建一个线程,进程里的第一个线程 ...

  5. linux 安装盘作为 repo

    1) CentOS 7.7 安装完之后, /etc/yum.repos.d 下面有很多.repo. 其中有一个CentOS-Media.repo. 编辑文件把enabled 改成 1 . 然后把其他. ...

  6. SQL Server 数据的增删改

    1. 使用Insert语句添加数据 (1)如果要向表中每一列都添加数据,则可以省略列明,直接将值按照顺序写入并用逗号隔开就行. use Howie ','JD','mars','CN','sh') ( ...

  7. LuaFramework 学习

    LuaFramework_UGUI_V2 https://github.com/jarjin/LuaFramework_UGUI_V2 using UnityEngine; using LuaInte ...

  8. PHP常用数字函数以及排序函数

    一:数字函数 .ceil() 进一取整 示例:ceil(0.9) 结果为1 .abs() 绝对值 示例:abs(-1) 结果为1 .rand() 随机数 示例:rand(1. 100) 1到100 以 ...

  9. js将内容复制到剪贴板

    有一需求,点击按钮要将某个值复制到剪贴板. 第一种,代码如下: <div cols="20" id="biao1">12345678</div ...

  10. torch_12_BigGAN全文解读

    1.摘要: 尽管近来生成图片模型取得了进步,成功生成了高分辨率的图片,但是在复杂的数据集中,样本的多样性仍然是难以捉摸的目标.本文尝试在大规模上训练生成对抗网络,并研究这种规模下的不稳定性.我们发现将 ...