掌握聚合最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务

container_of宏定义和作用 container_of原理和应用场景

在嵌入式开发和操作系统内核编程中,container_of 宏是一个非常重要的工具。它允许开发者通过结构体成员的地址反推出整个结构体的地址,从而实现对结构体的访问。这种能力在面向对象编程中尤为重要,特别是在 C 语言中,由于缺乏类的概念,container_of 宏弥补了这一缺陷。本文将详细介绍 container_of 宏的定义、工作原理以及其在实际开发中的应用场景。

一、container_of 宏的基本概念

  1. 什么是 container_of 宏

container_of 宏是一种宏定义,通常用于 C 语言中。它的作用是通过结构体中的某个成员变量的地址,推导出该成员所属的整个结构体的地址。这在链表、树等数据结构的操作中尤为重要。

  1. container_of 宏的作用

container_of 宏的主要作用是:

结构体成员定位:通过成员变量的地址,找到包含该成员的整个结构体。

类型安全:确保类型匹配,避免类型错误导致的运行时问题。

二、container_of 宏的定义

  1. 标准定义

在 Linux 内核中,container_of 宏的标准定义如下:

#define container_of(ptr, type, member) \
    ({ const typeof(((type *)0)->member) *__mptr = (ptr); \
       (type *)( (char *)__mptr - offsetof(type, member) ); })
  1. 各部分解析

typeof 关键字

typeof 是 GCC 提供的关键字,用于获取表达式的类型。在这里,它用于获取 member 成员的类型。

offsetof 宏

offsetof 是标准 C 库中的宏,用于计算结构体成员相对于结构体起始地址的偏移量(以字节为单位)。

类型转换

宏通过减去偏移量的方式,将成员变量的地址转换为整个结构体的地址。

三、container_of 宏的工作原理

  1. 偏移量计算

假设有一个结构体 struct example,其中包含一个成员变量 int data:

struct example {
    int data;
};

如果知道 data 的地址,可以通过 offsetof 宏计算其相对于结构体起始地址的偏移量:

size_t offset = offsetof(struct example, data);
  1. 地址转换

假设 ptr 是 data 成员的地址,通过以下公式可以计算出整个结构体的地址:

(char *)ptr - offset

最终的结果需要强制转换为结构体指针类型:

(struct example *)((char *)ptr - offset)
  1. 示例代码

以下是一个完整的示例代码,展示 container_of 宏的工作原理:

#include <stdio.h>
#include <stddef.h>
struct example {
    int data;
};
void print_container(void *ptr) {
    struct example *container = container_of(ptr, struct example, data);
    printf("Container address: %p\n", (void *)container);
}
int main() {
    struct example obj = { .data = 42 };
    int *data_ptr = &obj.data;
    print_container(data_ptr);
    return 0;
}

输出结果:

Container address: 0x7ffeeb8b9a10

四、container_of 宏的应用场景

  1. 链表操作

在链表中,节点通常包含指向下一个节点的指针,以及一些其他信息。通过 container_of 宏,可以从节点的指针反推出整个节点所在的结构体。

示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
struct node {
    int value;
    struct node *next;
};
#define container_of(ptr, type, member) \
    ({ const typeof(((type *)0)->member) *__mptr = (ptr); \
       (type *)( (char *)__mptr - offsetof(type, member) ); })
void print_list(struct node *head) {
    struct node *current = head;
    while (current != NULL) {
        printf("%d -> ", current->value);
        current = container_of(current->next, struct node, next);
    }
    printf("NULL\n");
}
int main() {
    struct node n1 = { .value = 1, .next = NULL };
    struct node n2 = { .value = 2, .next = NULL };
    n1.next = &n2;
    print_list(&n1);
    return 0;
}

输出结果:

1 -> 2 -> NULL
  1. 设备驱动程序

在设备驱动程序中,通常需要将设备结构体与设备文件关联起来。通过 container_of 宏,可以从文件描述符反推出设备结构体。

示例代码:

#include <stdio.h>
#include <stddef.h>
struct device {
    int id;
    char name[32];
};
#define container_of(ptr, type, member) \
    ({ const typeof(((type *)0)->member) *__mptr = (ptr); \
       (type *)( (char *)__mptr - offsetof(type, member) ); })
void print_device(void *dev_ptr) {
    struct device *dev = container_of(dev_ptr, struct device, name);
    printf("Device ID: %d, Name: %s\n", dev->id, dev->name);
}
int main() {
    struct device d = { .id = 1, .name = "USB Device" };
    print_device(d.name);
    return 0;
}

输出结果:

Device ID: 1, Name: USB Device
  1. 内核编程

在 Linux 内核中,container_of 宏被广泛用于实现链表、哈希表等数据结构。例如,在中断处理程序中,可以通过 container_of 宏从中断描述符反推出对应的设备结构体。

五、container_of 宏的优点

  1. 类型安全性

container_of 宏通过 typeof 和 offsetof 宏确保了类型的安全性,避免了手动计算偏移量可能导致的错误。

  1. 可移植性

container_of 宏基于标准 C 库的 offsetof 宏,因此具有良好的可移植性,可以在不同的编译器和平台上使用。

  1. 简化代码

通过 container_of 宏,开发者无需手动计算偏移量,简化了代码编写过程,提高了代码的可读性和维护性。

container_of 宏是 C 语言中一个非常实用的工具,尤其在嵌入式开发和操作系统内核编程中发挥了重要作用。通过结构体成员的地址,它可以反推出整个结构体的地址,从而实现对结构体的访问。本文详细介绍了 container_of 宏的定义、工作原理以及其在链表操作、设备驱动程序和内核编程中的应用场景。希望本文能帮助开发者更好地理解和使用 container_of 宏,从而提高代码的质量和效率。

声明:所有来源为“聚合数据”的内容信息,未经本网许可,不得转载!如对内容有异议或投诉,请与我们联系。邮箱:marketing@think-land.com

  • 车辆过户信息查询

    通过车辆vin码查询车辆的过户次数等相关信息

    通过车辆vin码查询车辆的过户次数等相关信息

  • 银行卡五元素校验

    验证银行卡、身份证、姓名、手机号是否一致并返回账户类型

    验证银行卡、身份证、姓名、手机号是否一致并返回账户类型

  • 高风险人群查询

    查询个人是否存在高风险行为

    查询个人是否存在高风险行为

  • 全球天气预报

    支持全球约2.4万个城市地区天气查询,如:天气实况、逐日天气预报、24小时历史天气等

    支持全球约2.4万个城市地区天气查询,如:天气实况、逐日天气预报、24小时历史天气等

  • 购物小票识别

    支持识别各类商场、超市及药店的购物小票,包括店名、单号、总金额、消费时间、明细商品名称、单价、数量、金额等信息,可用于商品售卖信息统计、购物中心用户积分兑换及企业内部报销等场景

    支持识别各类商场、超市及药店的购物小票,包括店名、单号、总金额、消费时间、明细商品名称、单价、数量、金额等信息,可用于商品售卖信息统计、购物中心用户积分兑换及企业内部报销等场景

0512-88869195
数 据 驱 动 未 来
Data Drives The Future