Linux内核中的链表定义为:struct list_head
- 初始化链表
单纯定义并初始化链表的两种方式:
方式一:
LIST_HEAD(mylist);
方式二:
struct list_head mylist = LIST_HEAD_INIT(mylist);
当链表嵌入到结构体中时,需要用另外的方式进行初始化
比如,定义如下结构体:
typedef struct list_test_s
{
char str[32];
struct list_head list;
int a;
}list_test_t;
list_test_t test_list={0};
初始化方式一:
list_head_init(&test_list.list);
初始化方式二:
INIT_LIST_HEAD(&test_list.list);
- 操作链表
向头部插入数据:list_add
向尾部插入数据:list_add_tail
删除数据:list_del
遍历链表的四种方式:
list_for_each
list_for_each_safe
list_for_each_entry
list_for_each_entry_safe
区别:
list_for_each和list_for_each_safe:用于遍历纯链表
list_for_each_entry和list_for_each_entry_safe:用于遍历嵌入链表的结构体
注意:list_for_each和list_for_each_safe如果结合list_entry使用的话,可以达到list_for_each_entry和list_for_each_entry_safe一样的效果
list_for_each和list_for_each_safe的区别:
list_for_each:遍历过程中不能删除节点
list_for_each_safe:遍历过程中可以删除节点
list_for_each_entry和list_for_each_entry_safe的区别:
list_for_each_entry:遍历过程中不能删除节点
list_for_each_entry_safe:遍历过程中可以删除节点
具体用法,详见下边的例子。
- list_entry的作用
已知结构体变量test_list中list的地址,推算出结构体变量test_list的地址
原理如下:
(unsigned int)&test_list.list - (unsigned int)&((list_test_t*)0)->list;
- 例子代码
typedef struct list_test_s
{
char str[32];
struct list_head list;
int a;
}list_test_t;
int main(int argc, char** argv)
{
//定义并初始化链表的两种方式
LIST_HEAD(mylist); //方式一
//struct list_head mylist = LIST_HEAD_INIT(mylist); //方式二
//嵌入到结构体中的链表的初始化方式
list_test_t test_list={0};
list_head_init(&test_list.list); //方式一
//INIT_LIST_HEAD(&test_list.list); //方式二
unsigned int add = (unsigned int)&test_list.list - (unsigned int)&((list_test_t*)0)->list;
printf("add:%u\n", add);
printf("&test_list:%u\n", &test_list);
//初始化
list_test_t a1={0};
strcpy(a1.str, "a1");
list_add_tail(&a1.list ,&test_list.list); //向链表尾部插入
list_test_t a2={0};
strcpy(a2.str, "a2");
list_add_tail(&a2.list ,&test_list.list);
list_test_t a3={0};
strcpy(a3.str, "a3");
list_add_tail(&a3.list ,&test_list.list);
list_test_t a4={0};
strcpy(a4.str, "a4");
list_add(&a4.list ,&test_list.list); //向链表头部插入
//遍历
struct list_head *pos = NULL, *tmp = NULL;
list_test_t *lt = NULL, *lt_tmp = NULL;
//遍历过程中可以删除节点
list_for_each_safe(pos ,tmp ,&test_list.list)
{
lt = list_entry(pos ,list_test_t ,list);
printf("ukey_name:[%s]\n" ,lt->str);
if(strcmp(lt->str, "a2") == 0)
list_del(pos);
}
printf("-------------------------\n");
//遍历过程中不可以删除节点
list_for_each(pos, &test_list.list)
{
lt = list_entry(pos ,list_test_t ,list);
printf("ukey_name:[%s]\n" ,lt->str);
}
printf("-------------------------\n");
//遍历过程中可以删除节点
list_for_each_entry_safe(lt, lt_tmp, &test_list.list, list)
{
printf("ukey_name:[%s]\n" ,lt->str);
if(strcmp(lt->str, "a3") == 0)
list_del(<->list);
}
printf("-------------------------\n");
//遍历过程中不可以删除节点
list_for_each_entry(lt, &test_list.list, list)
{
printf("ukey_name:[%s]\n" ,lt->str);
}
return 0;
}