结构体指offsetof宏详细解析

时间:2022-09-23 14:54:41

1、#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)     (include/linux/stddef.h)

1.1 功能:

返回结构体TYPE中MEMBER成员相对于结构体首地址的偏移量,以字节为单位。

1.2 解析:

此类复杂表达式的解析应该采用从内向外、逐层理解的方式。

首先,(TYPE *)0表示将数字0强制类型转换为TYPE类型(TYPE为结构体类型)的指针。因此这里的0代表内存地址0,即我们认为内存地址0开始的sizeof(TYPE)个字节内存储的是一个TYPE类型的变量。

然后,((TYPE *)0)->MEMBER 得到该结构体变量中的MEMBER成员变量,

而 &(((TYPE*)0)->MEMBER) 使用取地址符&取得了MEMBER成员变量的地址,(size_t)加在前面表示将MEMBER成员变量的地址强制类型转换为size_t(即unsigned int),并将结果作为宏的返回值。

可见,offsetof宏返回的是MEMBER成员在内存中的实际地址。又因为整个结构体的起始地址是0,因此MEMBER成员的实际地址在数值上就等于MEMBER成员相对于结构体首地址的偏移量。

1.3 扩展思考:

1.3.1 使用offsetof宏会影响内存0地址处的值吗?

答案是不会,从1.3.2可知offsetof宏的运算是在C编译器编译时完成的,因此内存的0地址在机器指令中根本未被操作,当然不会影响其值了。

1.3.2offsetof宏返回的MEMBER相对于结构体首地址的偏移量是如何得到的?->符号如何能正确寻址到结构体中某个成员变量?

想探究struct如何通过->精确寻址每一个成员,最好的办法就是将C代码汇编为.S的汇编语言代码,通过观察汇编代码可以看到C编译器对代码处理的具体细节。我们的示例代码如下:

#include"stdio.h"

#definemyoffsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

typedefstruct st

{

int a;

int c;     //将该行加上或去掉,对比得到的汇编代码的差别

short d;   //将该行加上或去掉,对比得到的汇编代码的差别

char b;

}st;

intgetoffsetof(void)

{

return myoffsetof(struct st, b);

}

将以上代码保存为offsetof.c,并且使用arm-linux-gcc offsetof.c –S执行汇编,则会得到offsetof.s文件,内容如下:

.file  "offsetof.c"

.text

.align 2

.global getoffsetof

.type  getoffsetof, %function

getoffsetof:

@ Function supports interworking.

@ args = 0, pretend = 0, frame = 0

@ frame_needed = 1, uses_anonymous_args= 0

mov    ip, sp        // 这三行

stmfd  sp!, {fp, ip, lr, pc}   // 是函数

sub    fp, ip, #4           // 栈帧保存

mov    r3, #10          // #10即是offsetof宏计算得到的值

mov    r0, r3        // 将返回值置于R0中

sub    sp, fp, #12      // 函数栈帧

ldmfd  sp, {fp, sp, lr}    // 恢复

bx     lr            // 函数返回

.size  getoffsetof, .-getoffsetof

.ident "GCC: (GNU) 4.1.2"

以上汇编代码中mov r3, #10一句可以看出,offsetof宏计算member的偏移量是C编译器在编译阶段完成的,而并不需要CPU在运行时去计算得出。

可以尝试着更改struct st中成员b之前的成员,然后再次汇编,对比汇编后代码的不同,以此来验证我们的推论。

结构体指offsetof宏详细解析的更多相关文章

  1. C语言 - 结构体(struct)比特字段(:) 详细解释

    结构体(struct)比特字段(:) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26722511 结构体(struc ...

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

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

  3. 结构体对齐及#pragma详细解释

    在linux下c语言结构体对齐: 1.自然对齐 struct 是一种复合数据类型,其构成元素既可以是基本数据类型(如int.long.float 等)的变量,也可以是一些复合数据类型(如array.s ...

  4. bmp文件格式详细解析

    先区分几个概念:16色和16位色一样吗? 不一样! 颜色位数,即是用多少位字节表示的值,每一位可以表示0和1两值.通常图片的颜色深度,简称色深,就是用位数来表示的,所以,我通常会看到8位色,16位色, ...

  5. Go第六篇之结构体剖析

    Go 语言通过用自定义的方式形成新的类型,结构体是类型中带有成员的复合类型.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性. Go 语言中的类型可以被实例化,使用new或&a ...

  6. Go语言中结构体的使用-第1部分结构体

    1 概述 结构体是由成员构成的复合类型.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性.结构体成员,也可称之为成员变量,字段,属性.属性要满足唯一性.结构体的概念在软件工程上 ...

  7. 06. Go 语言结构体

    Go语言结构体(struct) Go 语言通过用自定义的方式形成新的类型,结构体是类型中带有成员的复合类型.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性. Go 语言中的类 ...

  8. 【C语言】这种求结构体成员大小的方法,你可能需要了解一下~

    在C语言编程中,有时候需要知道某结构体中某成员的大小,比如使用堆内存来存储结构体中的某成员时,需要知道该成员的大小,才好确定所需申请的空间大小.求某结构体中某成员的大小,你会怎么做? 例子: type ...

  9. ARM单片机的头文件如何用结构体定义地址

    下面我们以ARM Cortex-M0内核单片机LPC1114的头文件lpc11xx.h文件进行说明. 1.先说两句 lpc11xx.h文件是lpc11xx系列单片机包含的头文件.这个文件的作用和51单 ...

随机推荐

  1. Oracle、MySql、SQLServer数据分页查询

    看过此博文后Oracle.MySql.SQLServer 数据分页查询,在根据公司的RegionRes表格做出了 SQLserver的分页查询语句: 别名.字段 FROM( SELECT row_nu ...

  2. Python中的库使用之一 PIL

    先上代码:本文主要工给自己参考,在需要的时候直接搜索查找就行了,不想看没有实际运行例子的文档,当参考完这部分还哦未能解决问题在参考PIL的相关文档! Skip to content This repo ...

  3. minify合并js和css文件

    压缩 JavaScript 和 CSS,是为减少文件大小,节省流量开销:合并 JavaScript 和 CSS,是为了减少请求数量,减轻服务器压力.而这些枯燥又没有技术含量的工作,我们以前通常会手动处 ...

  4. struts2 convention-plugin

    导入这个插件,该插件的作用是替换掉struts.xml 原则是没有配置,全是约定 基本步骤 1.新建HomeAction,里面有个execute方法return success,请求home.acti ...

  5. IIS7无后缀URL部署问题 MVC4 MVC URL映射 windows server 2008

    前言和中间一段都是我找到问题的过程和思维方法.没兴趣的可以直接跳过看后面的问题和解决. 前言: 问题发生在站点完成后,部署到服务器上.以为这个是最轻松的工作.结果悲剧了.windows server ...

  6. Spring3实战第二章第一小节 Spring bean的初始化和销毁三种方式及优先级

    Spring bean的初始化和销毁有三种方式 通过实现 InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法: 优先级第二通过 <bean& ...

  7. 用Elasticsearch构建电商搜索平台,一个极有代表性的基础技术架构和算法实践案例&lbrack;转&rsqb;

    原文链接:http://mp.weixin.qq.com/s?__biz=MzA5NzkxMzg1Nw==&mid=2653160642&idx=1&sn=608f4e6883 ...

  8. POJ - 2698 贪心

    经典面替换算法,每次选择最远的那个碟片请求进行替换. AC代码 #include <cstdio> #include <cmath> #include <algorith ...

  9. Mysql 地区经纬度 查询

    摘要: Mysql数据库,根据地区的经纬度信息,查询附近相邻的地区 2015-03-27 修改,增加 MySQL的空间扩展(MySQL Spatial Extensions)的解决方案: MySQL的 ...

  10. Mysql学习---全国省市区以及邮编数据库

    更多下载