1、前言

在C语言的结构体中,由于字节对齐的问题,所以成员的地址并不能直接根据数据类型的大小进行计算,使用宏offsetof可以获得结构体成员相对于结构体首地址的字节偏移量。

2、offsetof宏实现

在C标准库中offsetof的声明如下,需要包含头文件<stddef.h>:

  1. size_t offsetof(type, member);

参数:

type:结构体类型

member:结构体中成员的名称

返回值:

返回类型为size_t的值,表示type中member的偏移量

该宏在Linux内核源码内的实现如下:

  1. #define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)

通过上面这个宏为什么能获取到结构体某个成员的偏移地址呢?首先,偏移地址的计算方法为:

当前的成员地址-结构体首地址=偏移地址

在offsetof宏中,将0地址强制转换成了(TYPE *)类型,也就是说结构体的首地址为0,所以根据偏移地址计算方法,可以知道当前成员的地址也就等于偏移地址,所以宏offsetof将成员的地址取出并返回,获得的就是某个成员的偏移地址了,返回值为size_t类型,需要引起一定的注意。

3、实例

下面是一个offsetof的使用实例,代码如下所示:

  1. #include <stdio.h>
  2. #include <stddef.h>
  3. #include <stdlib.h>
  4.  
  5. struct s {
  6. int i;
  7. char c;
  8. double d;
  9. char a[];
  10. };
  11.  
  12. int main(int argc, char *argv[])
  13. {
  14. printf("sizeof(struct s)=%zd\n", sizeof(struct s));
  15. printf("offsets: i=%zd; c=%zd; d=%zd; a=%zd.\n",
  16. offsetof(struct s, i), offsetof(struct s, c),
  17. offsetof(struct s, d), offsetof(struct s, a));
  18.  
  19. exit(EXIT_SUCCESS);
  20. }

使用gcc编译后运行结果如下所示:

由于字节对齐的原因,所以结构体s的大小为16个字节,假设结构体首地址从0开始,由于int类型占用4字节,所以地址0到3为变量i所用,char类型占用1字节,地址4为变量c所用,由于需要字节对齐并且double类型的开始地址必须是8的整数倍,因此地址5到7被填充,double类型占用8字节,地址8到15被变量d所用,a的地址则从地址16开始,因此,通过宏offsetof便可以得到结构体成员的偏移地址。

参考:

https://www.runoob.com/cprogramming/c-macro-offsetof.html

https://www.cnblogs.com/litifeng/p/7685378.html

宏offsetof分析的更多相关文章

  1. container_of宏定义分析---linux内核

    问题:如何通过结构中的某个变量获取结构本身的指针??? 关于container_of宏定义在[include/linux/kernel.h]中:/*_** container_of - cast a ...

  2. 剖析linux内核中的宏-----------offsetof

    offsetof用于计算TYPE结构体中MEMBER成员的偏移位置. #ifndef offsetof#define offsetof(TYPE, MEMBER) ((size_t) &((T ...

  3. linux内核container_of宏定义分析

    看见一个哥们分析container_of很好,转来留给自己看 一.#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMB ...

  4. 《linux 内核全然剖析》 笔记 CODE_SPACE 宏定义分析

    在memory.c里面.遇到一个宏定义,例如以下: #define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \ current->sta ...

  5. 宏_CRTIMP分析

    CRTIMP是C run time implement的简写,C运行库的实现的意思. 作为用户代码,不应该使用这个东西. 该参数决定 运行时 到底用 动态链接库 还是静态链接 #ifndef _CRT ...

  6. C语言-宏定义与使用分析

    1.C语言中的宏定义 #define是预处理器处理的单元实体之— #define定义的宏可以出现在程序的任意位置 #define定义之后的代码都可以使用这个宏 2.定义宏常量 #define定义的宏常 ...

  7. offsetof宏---个人笔记

    标准库里面提供的offsetof(t,m)宏,用来计算两个变量在内存中的地址偏移量 #include <stdio.h>//原型: #define offsetof(TYPE, MEMBE ...

  8. 【宏蛋白组】iMetaLab平台分析肠道宏蛋白质组数据

    目录 一.iMetaLab简介 二.内置工具与模块 1. Data Processing module 2. Functional Analysis 3. R Developing environme ...

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

    关于结构体学习,需要了解:结构体的定义和使用.内存对齐.结构体指针.得到结构体元素的偏移量(offsetof宏实现) 一.复习结构体的基本定义和使用 typedef struct mystruct { ...

随机推荐

  1. JAVA WEB面试总结

    本文目录: 1. 什么是cookie 2. 什么是session 3.什么是Servlet,Servlet生命周期方法 4.JSP隐含对象 5.JSP的四个域对象的作用范围 6.转发和重定向的区别 7 ...

  2. Python学习笔记之try-except

    Python使用被称为异常的特殊对象来管理程序执行期间发生的错误.每当发生让Python不知所措的错误时,它都会创建一个异常对象.如果你编写了处理该异常的代码,程序将继续运行:如果你未对异常进行处理, ...

  3. JAVA中的四种JSON解析方式详解

    JAVA中的四种JSON解析方式详解 我们在日常开发中少不了和JSON数据打交道,那么我们来看看JAVA中常用的JSON解析方式. 1.JSON官方 脱离框架使用 2.GSON 3.FastJSON ...

  4. ES6 Set和Map集合(六)

    一.Set集合创建Set实例:let set = new Set();1.特性:a.Set本身是一个构造函数,用来生成Set数据结构[类比数组结构]b.Set函数可以接受具有Iterable接口的数据 ...

  5. QML 移动端适配一个参考思路

    参考: Qt Quick 准确的移动平台屏幕适配 qt qml 高宽自动适配android设备 QML 从无到有 (移动适配) 思路:以一个平台分辨率为基准(如320*480),考虑其与其它平台的比例 ...

  6. 易语言网页登录 POST

    使用精易模块 打开网页登录窗口 抓取数据 输入用户名密码,抓包 保存抓到的数据 包含post地址和数据信息 易语言代码 解决乱码

  7. 由于找不到mingwm10.dll 由于找不到QtCore4.dll

    出现如下错误: 由于找不到mingwm10.dll 由于找不到QtCore4.dll 解决办法 将qt库加入环境变量

  8. 2 Linux磁盘管理

    Linux磁盘管理:磁盘管理好坏直接关系到整个系统的性能问题常用三个命令:df.du.fdiskdf:列出文件系统的整体磁盘使用量 df 参数 目录或文件名 -a:理出所有文件系统,包括系统特有的 / ...

  9. js 字符串 有没有 像C# @ 那种 换行也可以显示的方法 \

  10. 通过vjudge刷Uva的题目(解决Uva网站打开慢的问题)

    最近在跟着算法竞赛入门经典刷题,发现Uva网站打开超级慢,进个主页面都需要好几秒.后来发现可以通过vjudge网站刷Uva的题目,很是方便,在这mark一下,顺便做一下推荐. vjudge网址:htt ...