+ -

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

时间:2025-06-17

来源:互联网

标签: PHP教程

在手机上看
手机扫描阅读

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

一、container_of 宏的基本概念

  • 什么是 container_of 宏

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

  • container_of 宏的作用

  • container_of 宏的主要作用是:

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

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

    二、container_of 宏的定义

  • 标准定义

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

    #definecontainer_of(ptr,type,member)\
    ({consttypeof(((type*)0)->member)*__mptr=(ptr);\
    (type*)((char*)__mptr-offsetof(type,member));})
  • 各部分解析

  • typeof 关键字

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

    offsetof 宏

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

    类型转换

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

    三、container_of 宏的工作原理

  • 偏移量计算

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

    structexample{
    intdata;
    };

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

    size_toffset=offsetof(structexample,data);
  • 地址转换

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

    (char*)ptr-offset

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

    (structexample*)((char*)ptr-offset)
  • 示例代码

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

    #include<stdio.h>
    #include<stddef.h>
    structexample{
    intdata;
    };
    voidprint_container(void*ptr){
    structexample*container=container_of(ptr,structexample,data);
    printf("Containeraddress:%p\n",(void*)container);
    }
    intmain(){
    structexampleobj={.data=42};
    int*data_ptr=&obj.data;
    print_container(data_ptr);
    return0;
    }

    输出结果:

    Containeraddress:0x7ffeeb8b9a10

    四、container_of 宏的应用场景

  • 链表操作

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

    示例代码:

    #include<stdio.h>
    #include<stdlib.h>
    #include<stddef.h>
    structnode{
    intvalue;
    structnode*next;
    };
    #definecontainer_of(ptr,type,member)\
    ({consttypeof(((type*)0)->member)*__mptr=(ptr);\
    (type*)((char*)__mptr-offsetof(type,member));})
    voidprint_list(structnode*head){
    structnode*current=head;
    while(current!=NULL){
    printf("%d->",current->value);
    current=container_of(current->next,structnode,next);
    }
    printf("NULL\n");
    }
    intmain(){
    structnoden1={.value=1,.next=NULL};
    structnoden2={.value=2,.next=NULL};
    n1.next=&n2;
    print_list(&n1);
    return0;
    }

    输出结果:

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

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

    示例代码:

    #include<stdio.h>
    #include<stddef.h>
    structdevice{
    intid;
    charname[32];
    };
    #definecontainer_of(ptr,type,member)\
    ({consttypeof(((type*)0)->member)*__mptr=(ptr);\
    (type*)((char*)__mptr-offsetof(type,member));})
    voidprint_device(void*dev_ptr){
    structdevice*dev=container_of(dev_ptr,structdevice,name);
    printf("DeviceID:%d,Name:%s\n",dev->id,dev->name);
    }
    intmain(){
    structdeviced={.id=1,.name="USBDevice"};
    print_device(d.name);
    return0;
    }

    输出结果:

    DeviceID:1,Name:USBDevice
  • 内核编程

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

    五、container_of 宏的优点

  • 类型安全性

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

  • 可移植性

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

  • 简化代码

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

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

    以上就是php小编整理的全部内容,希望对您有所帮助,更多相关资料请查看php教程栏目。