| 关键词: nbsp list head struct member 成员 miscdevice type 变量 指针 |
现在我们看看设备驱动是如何使用链表维护设备列表的,首先,我们看一下 struct miscdevice { int minor; const char *name; const struct file_operations *fops; struct list_head list; struct device *parent; struct device *this_device; const char *nodename; mode_t mode; }; 可以看到 static LIST_HEAD(misc_list);这个定义宏展开,可以看到是用于定义 #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
#define LIST_HEAD_INIT(name) { &(name), &(name) }现在我看可以看一下函数 INIT_LIST_HEAD(&misc->list); 这个操作与 static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } 接下来,在通过函数 list_add(&misc->list, &misc_list); 内核的 static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } 函数实现很简单,就是入参转换为三个参数后调用内部
static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } 这里设置了新添加结点的 这里还有一个问题,就是如何获取链表中的数据, #define list_entry(ptr, type, member)
container_of(ptr, type, member)这里有三个参数
举例如下: const struct miscdevice *p = list_entry(v, struct miscdevice, list) 接下来我们就够访问 #define list_entry(ptr, type, member)
container_of(ptr, type, member)其实现非常简单,就是使用入参调用 #define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );}) 注意,宏使用了大括号表达式,对于大括号表达式,编译器会展开所有表达式,同时使用最后一个表达式的结果进行返回。 举个例子: #include <stdio.h> int main() { int i = 0; printf("i = %dn", ({++i; ++i;})); return 0; } 输出结果为 另一个关键是 #include <stdio.h> struct s { int field1; char field2; char field3; }; int main() { printf("%pn", &((struct s*)0)->field3); return 0; } 输出结果为 还有一个专门用于获取结构体中某个成员变量偏移的宏,其实现与前面提到的宏非常类似: #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)这里对 当然
未了,需要说的是,内核代码中并不仅仅只有上述这些接口。 |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|