1、前言

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

2、offsetof宏实现

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

size_t offsetof(type, member);

参数:

type:结构体类型

member:结构体中成员的名称

返回值:

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

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

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

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

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

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

3、实例

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

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h> struct s {
int i;
char c;
double d;
char a[];
}; int main(int argc, char *argv[])
{
printf("sizeof(struct s)=%zd\n", sizeof(struct s));
printf("offsets: i=%zd; c=%zd; d=%zd; a=%zd.\n",
offsetof(struct s, i), offsetof(struct s, c),
offsetof(struct s, d), offsetof(struct s, a)); exit(EXIT_SUCCESS);
}

使用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. asp.net core流式上传大文件

    asp.net core流式上传大文件 首先需要明确一点就是使用流式上传和使用IFormFile在效率上没有太大的差异,IFormFile的缺点主要是客户端上传过来的文件首先会缓存在服务器内存中,任何 ...

  2. Centos7 Putty SSH密钥登录

    在本地电脑打开PuTTYgen程序,点击Generate生成密钥,可以再设置一层密码,保存公钥和私钥到本地文件,保存好,最好多处备份 先用密码登录远程Centos vim ~/.ssh/authori ...

  3. es6中的arrowfunction

    es6新增箭头函数,主要解决了以下几点问题 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象. 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误. 不可以使用 ...

  4. 【MySQL】备份和恢复

    语法 mysqldump -uslave -p -h127.0.0.1 --single-transaction --set-gtid-purged=OFF database1 table1 tabl ...

  5. itextpdf5生成document生成pdf的简单dome

    package dbzx.pdf; import java.io.FileNotFoundException; import java.io.FileOutputStream; import org. ...

  6. 01、Linux基础命令

    linux 一些主要目录的认识: /bin 二进制可执行命令 /boot 存放系统引导文件,如 内核.grub 等 /dev 设备文件 /etc 系统配置目录 /home 普通用户家目录 /lib 系 ...

  7. SpringBoot配置多注册中心(yml,properties)

    dubbo-2.6.6 dubbo.config.multiple=true    dubbo.registries.z1.timeout = 5000    dubbo.registries.z1. ...

  8. 大数据技术原理与应用:【第二讲】大数据处理架构Hadoop

    2.1 Hadoop概论 创始人:Doug Cutting 1.简介: 开源免费; 操作简单,极大降低使用的复杂性; Hadoop是Java开发的; 在Hadoop上开发应用支持多种编程语言.不限于J ...

  9. 数据结构篇——字典树(trie树)

    引入 现在有这样一个问题, 给出\(n\)个单词和\(m\)个询问,每次询问一个单词,回答这个单词是否在单词表中出现过. 好像还行,用 map<string,bool> ,几行就完事了. ...

  10. HDU6583:Typewriter(dp+后缀自动机)

    传送门 题意: 给出\(p,q\),现在要你生成一个字符串\(s\). 你可以进行两种操作:一种是花费\(p\)的代价随意在后面添加一个字符,另一种是花费\(q\)的代价可以随意赋值前面的一个子串. ...