简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
🍉🍉🍉文章目录🍉🍉🍉
- 🌻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
是一个结构体类型,member
是type
结构体中的一个成员。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)中的
vector
、list
、map
等容器。在这些容器中,我们通常需要获取元素类型中的某个成员的偏移量,以便在内存中正确地定位和访问这些成员。 - 例如,假设我们有一个结构体
MyStruct
,它有两个成员a
和b
:
struct MyStruct {
int a;
char b;
};
- 我们可以使用offsetof宏来获取成员
a
和b
相对于结构体开头的偏移量:
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 的值。