简介: 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 的值。
 



















