offsetof与container_of宏[总结]

简介: offsetof 和 container_of 宏是 C 语言中常用于结构体操作的两个宏,它们帮助程序员处理指针偏移和结构体的成员与结构体本身之间的关系。下面是对这两个宏的总结及其应用的详细介绍。
  1. offsetof 宏

作用

offsetof 宏用来获取结构体成员相对于结构体起始位置的偏移量。它返回一个 size_t 类型的值,表示成员在结构体中的偏移。

定义

在 头文件中定义:

define offsetof(type, member) ((size_t)&(((type *)0)->member))

php
64 Bytes
© 菜鸟-创作你的创作
用法

type: 结构体类型。
member: 结构体成员。
offsetof(type, member) 的作用是返回 member 成员相对于 type 类型结构体首地址的偏移值。

示例

include

include

struct Person {
int age;
char name[20];
};
int main() {
printf("Offset of age: %zu\n", offsetof(struct Person, age));
printf("Offset of name: %zu\n", offsetof(struct Person, name));
return 0;
}
php
254 Bytes
© 菜鸟-创作你的创作
输出:

Offset of age: 0
Offset of name: 4
php
34 Bytes
© 菜鸟-创作你的创作
解释:

age 成员位于结构体的起始位置,因此偏移量为 0。
name 成员紧随其后,假设 int 占 4 字节,那么 name 的偏移量是 4。

  1. container_of 宏

作用

container_of 宏用来根据结构体成员的地址获取指向该结构体的指针。它实现了从结构体的成员指针逆推回结构体指针的功能。

定义

define container_of(ptr, type, member) \

((type *)((char *)(ptr) - offsetof(type, member)))

php
96 Bytes
© 菜鸟-创作你的创作
ptr: 指向结构体成员的指针。
type: 结构体类型。
member: 结构体的成员。
原理

ptr 是指向成员的指针。
offsetof(type, member) 计算出成员相对于结构体起始位置的偏移量。
通过 ptr 减去偏移量就能得到结构体的起始地址,即结构体指针。
示例

假设你有以下结构体:

include

include

struct Person {
int age;
char name[20];
};
int main() {
struct Person person = {25, "John"};
int ptr = &person.age;
struct Person
person_ptr = container_of(ptr, struct Person, age);
printf("Person's age: %d\n", person_ptr->age);
printf("Person's name: %s\n", person_ptr->name);
return 0;
}
php
367 Bytes
© 菜鸟-创作你的创作
输出:

Person's age: 25
Person's name: John
php
36 Bytes
© 菜鸟-创作你的创作
解释:

ptr 是指向 person.age 的指针。
container_of(ptr, struct Person, age) 通过 age 成员的偏移量计算出 person 结构体的起始地址,即获得 person_ptr 指针。
然后可以使用 person_ptr 访问结构体的其他成员。
offsetof 和 container_of 的关系

offsetof 主要用于获取结构体成员相对于结构体起始位置的偏移量,帮助我们计算结构体成员的内存位置。
container_of 则反过来,利用成员的指针和偏移量推算出包含该成员的结构体指针。它用于从成员指针恢复出结构体指针,特别在链表操作或遍历中非常常见。
实际应用场景

链表操作:
在内核编程(如 Linux 内核)中,链表节点结构常常嵌入在结构体中,使用 container_of 宏可以方便地从链表节点指针获取完整的结构体指针。struct list_head { struct list_head next, prev; }; struct Person { int age; char name[20]; struct list_head list; }; void print_person_info(struct list_head node) { struct Person person = container_of(node, struct Person, list); printf("Age: %d, Name: %s\n", person->age, person->name); }
事件处理和回调:
在事件驱动的编程中,回调函数常常会传递结构体成员的指针,通过 container_of 可以还原出回调函数所属的整个结构体指针。
数据结构优化:
在自定义的数据结构中,可能会嵌入结构体的部分成员,并使用 container_of 来高效地从数据结构的部分恢复完整的结构体指针。
总结

offsetof:用于计算结构体成员相对于结构体首地址的偏移量,通常用于需要处理内存布局和数据结构的场景。
container_of:用于通过结构体成员的指针逆推出包含该成员的结构体指针,广泛应用于内核编程、数据结构(如链表)操作中。
这两个宏可以帮助开发者在内存管理和数据结构操作时更加高效地进行指针运算,减少内存访问错误,并提升代码的可读性和可维护性。
https://www.52runoob.com/archives/4202

目录
相关文章
|
编译器 C语言
【C语言】深入理解EOF
【C语言】深入理解EOF
|
5月前
|
安全 Linux 网络安全
Linux系统怎么设置允许root登录
在 Linux 系统中,允许 root 用户 通过 SSH 登录是通过修改 SSH 配置文件 /etc/ssh/sshd_config 中的 PermitRootLogin 参数来实现的。默认情况下,出于安全考虑,很多 Linux 发行版会禁用 root 用户的 SSH 登录。因此,你可以按照以下步骤来允许 root 用户通过 SSH 登录:
611 0
|
6月前
|
机器学习/深度学习 数据可视化 算法
数据分布不明确?5个方法识别数据分布,快速找到数据的真实规律
本文深入探讨了数据科学中分布识别的重要性及其实践方法。作为数据分析的基础环节,分布识别影响后续模型性能与分析可靠性。文章从直方图的可视化入手,介绍如何通过Python代码实现分布特征的初步观察,并系统化地讲解参数估计、统计检验及distfit库的应用。同时,针对离散数据、非参数方法和Bootstrap验证等专题展开讨论,强调业务逻辑与统计结果结合的重要性。最后指出,正确识别分布有助于异常检测、数据生成及预测分析等领域,为决策提供可靠依据。作者倡导在实践中平衡模型复杂度与实用性,重视对数据本质的理解。
494 3
数据分布不明确?5个方法识别数据分布,快速找到数据的真实规律
|
5月前
|
Ubuntu 编译器 C语言
在Ubuntu22.04平台上交叉编译针对Rv1126架构的GCC13.2.0编译器的步骤。
遵循上述步骤,您应该能够在Ubuntu 22.04平台上成功交叉编译适用于RISC-V架构RV1126的GCC 13.2.0编译器,允许您为目标硬件构建应用程序和操作系统组件。
258 10
|
5月前
|
人工智能 缓存 测试技术
从零搭建智能搜索代理:LangGraph + 实时搜索 + PDF导出完整项目实战
本系统的核心特性包括:基于智能判断机制的自动网络搜索触发、跨多轮对话的上下文状态管理、多策略搜索机制与智能回退、透明的信息源追溯体系,以及专业级PDF文档生成功能。
229 0
|
人工智能 编解码 算法
MVPaint:腾讯PCG联合多所高校共同推出的3D纹理生成框架
MVPaint是由腾讯PCG联合多所高校共同推出的3D纹理生成框架,基于同步多视角扩散技术,实现高分辨率、无缝且多视图一致的3D纹理生成。该框架包含三个核心模块:同步多视角生成、空间感知3D修补和UV细化,显著提升3D模型的纹理生成效果。
219 2
MVPaint:腾讯PCG联合多所高校共同推出的3D纹理生成框架
|
数据采集 SQL 安全
2024年护网行动全国各地面试题汇总(5)
2024年护网行动全国各地面试题汇总(5)
|
存储 弹性计算 编解码
阿里云服务器通用型g8a实例最新收费标准与性能介绍
阿里云ECS通用型g8a服务器采用阿里云全新CIPU架构,可提供稳定的算力输出、更强劲的I/O引擎以及芯片级的安全加固。ECS通用型g8a实例支持开启或关闭超线程配置,单台g8a实例最高支持100万IOPS。阿里云ECS通用型g8a实例CPU采用AMD EPYCTM Genoa处理器,主频2.7 GHz,睿频最高3.7 GHz,计算性能稳定。本文为大家介绍通用型g8a实例最新收费标准及性能。
阿里云服务器通用型g8a实例最新收费标准与性能介绍
|
缓存 监控 Linux
Linux系统之smem命令的基本使用
【7月更文挑战第1天】Linux系统之smem命令的基本使用
375 3
|
C++ Unix Windows
面向 C++ 的现代 CMake 教程(四)(3)
面向 C++ 的现代 CMake 教程(四)
234 0