您好,登录后才能下订单哦!
# C语言宏函数container_of()怎么使用
## 引言
在Linux内核开发中,`container_of()`宏是一个极其重要且常用的工具。它能够通过结构体成员的地址反向推导出整个结构体的起始地址,这种技术在链表、设备驱动等场景中广泛应用。本文将深入解析`container_of()`的原理、使用方法以及实际应用案例。
---
## 一、container_of()宏概述
### 1.1 什么是container_of()
`container_of()`是Linux内核中定义的一个宏,其作用是通过结构体中某个成员的地址,计算出该结构体的起始地址。这种技术在内核数据结构(如链表、设备驱动模型)中被频繁使用。
### 1.2 宏定义源码
```c
// Linux内核中的定义(简化版)
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
offsetof(type, member)
是一个标准库宏,用于计算结构体成员相对于结构体起始地址的偏移量。例如:
struct sample {
int a;
char b;
double c;
};
// 假设double在64位系统偏移量为8
size_t offset = offsetof(struct sample, c); // 可能返回8
以container_of(&obj->member, struct obj, member)
为例:
1. 通过typeof
获取成员的类型并做类型检查
2. 使用offsetof
计算成员偏移量
3. 将成员指针转换为char*
(确保字节级计算)
4. 减去偏移量得到结构体起始地址
内核链表list_head
的典型用法:
struct task_struct {
int pid;
struct list_head tasks; // 嵌入的链表节点
};
// 通过tasks节点获取task_struct
struct task_struct *task = container_of(ptr, struct task_struct, tasks);
#include <stdio.h>
#include <stddef.h>
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
struct student {
int id;
char name[20];
float score;
};
int main() {
struct student stu = {101, "Alice", 95.5};
float *score_ptr = &stu.score;
// 通过score成员反推student结构体
struct student *s = container_of(score_ptr, struct student, score);
printf("ID: %d, Name: %s\n", s->id, s->name);
return 0;
}
输出结果:
ID: 101, Name: Alice
typeof
和指针强制转换确保了类型安全。如果错误地传递了成员名,编译时会报错。
原始实现依赖GCC扩展语法({...})
,在其他编译器中可能需要改写:
// 替代方案
#define container_of(ptr, type, member) \
((type *)((char *)(ptr) - offsetof(type, member)))
container_of()
在运行时只有简单的指针运算,没有性能开销。
对于多层嵌套的结构体,可以链式调用:
struct A {
struct B b;
};
struct B {
int val;
};
struct B *b_ptr = &obj.a.b;
struct A *a_ptr = container_of(b_ptr, struct A, b);
#define get_container(ptr, member) \
container_of(ptr, typeof(*ptr), member)
C++中可以通过:
reinterpret_cast<T*>(reinterpret_cast<char*>(ptr) - offsetof(T, member))
实现类似功能,但缺乏编译时类型检查。
这种技术实现了类似”子类通过基类指针向上转型”的效果。
在kernel/sched/core.c
中,通过task_struct
的se
成员获取任务指针:
struct task_struct *p = container_of(se, struct task_struct, se);
struct device
嵌入到具体设备结构中时,常用此宏反向引用。
container_of()
宏展示了C语言指针操作的强大能力,其核心思想可以归纳为:
1. 通过成员地址减去偏移量得到基地址
2. 依赖编译器的类型检查保证安全
3. 在资源受限环境下实现高效的对象定位
掌握这个宏对于理解Linux内核和开发高性能C程序至关重要。
#ifndef container_of
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
注意:实际内核代码还包含额外的编译器属性检查,本文为简化说明进行了适当裁剪。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。