C语言之offsetof实现分析(九十一)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

    • 🌻1.前言
    • 🌻2.C语言之offsetof介绍
    • 🌻3.代码实例
      • 🐓3.1 offsetof宏结构解析
      • 🐓3.2 计算结构体成员的偏移量
      • 🐓3.3 通过偏移量访问结构体成员
      • 🐓3.4 在动态分配的结构体数组中使用偏移量

🌻1.前言

本篇目的:C语言之offsetof实现分析

🌻2.C语言之offsetof介绍

  • C语言中的offsetof宏是一个非常有用的工具,它用于计算结构体中某个成员相对于结构体开头的偏移量。这个宏定义在头文件<stddef.h>中,它是C标准库的一部分。
  • offsetof宏的使用方法非常简单,它的原型如下:
offsetof(type, member);
  • 其中,type是一个结构体类型,membertype结构体中的一个成员。offsetof宏的返回值是member成员相对于type结构体开头的字节偏移量。
  • offsetof宏的实现通常依赖于编译器的特性,但一般情况下,它可以像下面这样实现:
#define offsetof(type, member) ((size_t)&(((type *)0)->member))
  • 这里,(type *)0将一个指向类型为type的结构的指针设置为地址0。这样做是合法的,因为offsetof宏不会解引用这个指针。然后,我们取member的地址,由于结构体的地址是0,所以member的地址就是member相对于结构体开头的偏移量。最后,我们将这个地址转换为size_t类型的值,这个值就是offsetof宏的返回值。
  • offsetof宏的一个常见用途是在实现泛型容器类时,比如C++的标准模板库(STL)中的vectorlistmap等容器。在这些容器中,我们通常需要获取元素类型中的某个成员的偏移量,以便在内存中正确地定位和访问这些成员。
  • 例如,假设我们有一个结构体MyStruct,它有两个成员ab
struct MyStruct {
    int a;
    char b;
};
  • 我们可以使用offsetof宏来获取成员ab相对于结构体开头的偏移量:
size_t offset_a = offsetof(MyStruct, a);
size_t offset_b = offsetof(MyStruct, b);
  • 在这个例子中,offset_a的值将是0,因为a是结构体的第一个成员,所以它位于结构体的开头。offset_b的值将是4(假设一个int类型占4个字节),因为b位于a之后。
  • 需要注意的是,offsetof宏只能用于结构体和联合体的成员,不能用于数组的元素或者普通的变量。此外,offsetof宏的返回值是size_t类型的,这是一个无符号整数类型,它能够表示任何非负的整数。
  • 总的来说,offsetof宏是一个非常实用的工具,它可以帮助我们方便地获取结构体成员的偏移量,从而在内存中正确地访问和操作这些成员。

🌻3.代码实例

🐓3.1 offsetof宏结构解析

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)
  • TYPE 是结构体的类型;
  • MEMBER 是结构体中的成员名称。
  • 这个宏的作用是计算结构体中某个成员的偏移量,也就是该成员相对于结构体起始地址的偏移量。

宏展开的过程如下:

  • (TYPE*)0:将 0 转换为 TYPE* 类型的指针,这里的目的是获取一个指向类型 TYPE 的空指针。
  • &((TYPE*)0)->MEMBER:获取成员 MEMBER 在结构体 TYPE 中的地址。这里 (TYPE*)0 指向结构体的起始地址,然后使用 -> 运算符访问成员 MEMBER,并取得其地址。
  • ((size_t) &((TYPE*)0)->MEMBER):将成员地址的指针类型转换为 size_t 类型,这是因为偏移量通常是用无符号整数表示的。
    最终结果是结构体成员 MEMBER 相对于结构体起始地址的偏移量,以字节为单位。

🐓3.2 计算结构体成员的偏移量

#include <stdio.h>
#include <stddef.h>

struct Example {
    int x;
    int y;
    char z;
};

int main() {
    printf("Offset of x: %zu\n", offsetof(struct Example, x));
    printf("Offset of y: %zu\n", offsetof(struct Example, y));
    printf("Offset of z: %zu\n", offsetof(struct Example, z));

    return 0;
}

  • 使用 offsetof 宏来获取结构体 Example 中各个成员的偏移量。

🐓3.3 通过偏移量访问结构体成员

#include <stdio.h>
#include <stddef.h>

struct Example {
    int x;
    int y;
    char z;
};

int main() {
    struct Example obj;
    int* ptr_y = (int*)((char*)&obj + offsetof(struct Example, y));
    *ptr_y = 10;

    printf("obj.y: %d\n", obj.y);

    return 0;
}

  • 使用偏移量来访问结构体成员 y。
  • 通过将结构体的地址与偏移量相加,我们可以得到成员 y 的地址,并将其视为整型指针,然后通过这个指针修改成员 y 的值。

🐓3.4 在动态分配的结构体数组中使用偏移量

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>

struct Example {
    int x;
    int y;
    char z;
};

int main() {
    int num_objects = 5;
    struct Example* array = malloc(num_objects * sizeof(struct Example));

    for (int i = 0; i < num_objects; i++) {
        int* ptr_x = (int*)((char*)&array[i] + offsetof(struct Example, x));
        *ptr_x = i;
    }

    for (int i = 0; i < num_objects; i++) {
        printf("array[%d].x = %d\n", i, array[i].x);
    }

    free(array);
    return 0;
}

  • 动态分配的结构体数组中使用偏移量来访问并设置成员 x 的值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/544238.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

做一个后台项目的架构

后台架构的11个维度 架构1&#xff1a;团队协助基础工具链的选型和培训架构2&#xff1a;搭建微服务开发基础设施架构3&#xff1a;选择合适的RPC框架架构4&#xff1a;选择和搭建高可用的注册中心架构5&#xff1a;选择和搭建高可用的配置中心架构6&#xff1a;选择和搭建高性…

React 19 的新增功能:Action Hooks

React 是前端开发领域最流行的框架之一。我喜欢 React 是因为它背后的团队和社区对它的热情。当社区提出新功能和改进的需求时&#xff0c;团队会倾听&#xff0c;React 的未来是令人兴奋和有趣的。 让我们来看一下 React 19 中令开发人员提升开发效率的新特性。对于每个钩子&…

STL--list双向链表

功能 将数据进行链式存储 链表&#xff08;list&#xff09;是一种物理存储单元上非连续的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接实现的 链表的组成&#xff1a;链表由一系列结点组成 结点的组成&#xff1a;一个是存储数据元素的数据域&#xff0…

FJSP:袋鼠群优化(Kangaroo Swarm Optimization ,KSO)算法求解柔性作业车间调度问题(FJSP),提供MATLAB代码

一、柔性作业车间调度问题 柔性作业车间调度问题&#xff08;Flexible Job Shop Scheduling Problem&#xff0c;FJSP&#xff09;&#xff0c;是一种经典的组合优化问题。在FJSP问题中&#xff0c;有多个作业需要在多个机器上进行加工&#xff0c;每个作业由一系列工序组成&a…

传统图机器学习的特征工程-连接

概念及应用场景 通过已知连接补全未知连接 将link编码成为向量输入到机器学习模型中&#xff1a; 1.直接提取link的特征&#xff0c;构建D维向量 2.把link两段节点的D维向量拼在一起&#xff08;丢失了link本身的连接结构信息&#xff09; 应用&#xff1a; 1.客观静态图…

webrtc中的Track,MediaChannel,MediaStream

文章目录 Track,MediaChannel,MediaStream的关系MediaStream的创建流程创建VideoChannel的堆栈创建VideoStream的堆栈 sdp中媒体参数信息的映射sdp中媒体信息参数设置体系参数设置流程参数映射体系 Track,MediaChannel,MediaStream的关系 Audio/Video track&#xff0c;MediaC…

Spring Boot | Spring Boot中进行 “文件上传” 和 “文件下载”

目录: 一、SpringBoot中进行 " 文件上传" :1.编写 "文件上传" 的 “表单页面”2.在全局配置文件中添加文件上传的相关配置3.进行文件上传处理&#xff0c;实现 "文件上传" 功能4.效果测试 二、SpringBoot中进行 "文件下载" :“英文名称…

【opencv】示例-stereo_match.cpp 立体匹配:通过对左右视图图像进行处理来生成视差图和点云数据...

/** stereo_match.cpp* calibration** 创建者 Victor Eruhimov&#xff0c;日期为 2010年1月18日。* 版权所有 2010 Argus Corp.**/#include "opencv2/calib3d/calib3d.hpp" // 导入OpenCV相机标定和三维重建相关的头文件 #include "opencv2/imgproc.hpp&qu…

stm32移植嵌入式数据库FlashDB

本次实验的程序链接stm32f103FlashDB嵌入式数据库程序资源-CSDN文库 一、介绍 FlashDB 是一款超轻量级的嵌入式数据库&#xff0c;专注于提供嵌入式产品的数据存储方案。与传统的基于文件系统的数据库不同&#xff0c;FlashDB 结合了 Flash 的特性&#xff0c;具有较强的性能…

【GD32】INA226电压电流功率检测模块

2.46 INA226电压电流功率检测模块 2.46.1 模块来源​ 采购链接&#xff1a;​ INA226电压电流功率检测模块 资料下载&#xff1a;&#xff08;基于该模块的资料&#xff0c;百度云链接等&#xff09;​ 链接&#xff1a;http://pan.baidu.com/s/1c0DbuXa 密码&#xff1a;3p2…

开源版中文和越南语贷款源码贷款平台下载 小额贷款系统 贷款源码运营版

后台 代理 前端均为vue源码&#xff0c;前端有中文和越南语 前端ui黄色大气&#xff0c;逻辑操作简单&#xff0c;注册可对接国际短信&#xff0c;可不对接 用户注册进去填写资料&#xff0c;后台审批&#xff0c;审批状态可自定义修改文字显示 源码免费下载地址抄笔记 (chaob…

Abstract Factory抽象工厂模式详解

模式定义 提供一个创建一系列相关或互相依赖对象的接口&#xff0c;而无需指定它们具体的类。 代码示例 public class AbstractFactoryTest {public static void main(String[] args) {IDatabaseUtils iDatabaseUtils new OracleDataBaseUtils();IConnection connection …

架构师系列-搜索引擎ElasticSearch(六)- 映射

映射配置 在创建索引时&#xff0c;可以预先定义字段的类型&#xff08;映射类型&#xff09;及相关属性。 数据库建表的时候&#xff0c;我们DDL依据一般都会指定每个字段的存储类型&#xff0c;例如&#xff1a;varchar、int、datetime等&#xff0c;目的很明确&#xff0c;就…

oarcle 19c ADG补丁升级(19.3-19.22)

一、备库操作 1.关闭备库数据库实例 sqlplus / as sysdba startup shutdown immediate # 查看oracle进程 ps -ef | grep sqlplus 2.关闭监听 lsnrctl start lsnrctl stop lsnrctl status 3.升级Opatch # 备份当前Opatch目录 su - oracle cd $ORACLE_HOME mv OPatch OPat…

康耐视visionpro-CogFindLineTool操作工具详细说明

◆CogFindeLineTool功能说明: 检测图像的直线边缘,实现边缘的定位、测量。 ◆CogFindeLineTool操作说明: ①.打开工具栏,双击或点击鼠标拖拽添加CogFindLineTool工具 ②.添加输入图像,点击鼠标右键“链接到”选择输入图像或以连线拖拽的方式选择相应输入图像 ③.所选空间…

Git-常规用法-含解决分支版本冲突解决方法

前置条件 已经创建了Gitee账号 创建一个远程仓库 个人主页-新建一个仓库-起好仓库名字-简介 远程仓库地址 Git的优点 Git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。于2005年以GPL发布。采用了分布式版本库的做法&…

深入探索 RabbitMQ:功能丰富的消息中间件一

在现代分布式系统的构建中&#xff0c;消息中间件扮演着至关重要的角色。作为这一领域的佼佼者&#xff0c;RabbitMQ以其独特的特性和强大的功能&#xff0c;为应用程序提供了高效可靠的消息传递解决方案。以下是对RabbitMQ及其显著特点的更详细探讨。 什么是 RabbitMQ&#x…

考试酷基本功修炼课学习历程_FPGA成长篇

本文为明德扬原创文章&#xff0c;转载请注明出处&#xff01;作者&#xff1a;明德扬学员&#xff1a;考试酷账号&#xff1a;11167760 我是硬件工程师&#xff0c;日常工作中主要跟数字电路、模拟电路、嵌入式系统打交道&#xff0c;当然也会涉及到FPGA&#xff0c;但是苦于…

【Vue】新手一步一步安装 vue 语言开发环境

文章目录 1、下载node.js安装包 1、下载node.js安装包 1.打开node.js的官网下载地址&#xff1a;http://nodejs.cn/download/ 选择适合自己系统的安装包&#xff1a;winds、mac 2. 配置node.js和npm环境变量 安装好之后&#xff0c;对npm安装的全局模块所在路径以及缓存所在路…

05.MySQL索引事务

1. 索引 1.1 概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。 可以对表中的一列或多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各自的数据结构实现 1.2 作用 数据库中的表、数据、索引之间的关系&#xff0c;类似于书架上的…