Linux内核学习之list链表

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(&lt->list);
	}
	printf("-------------------------\n");
	//遍历过程中不可以删除节点
	list_for_each_entry(lt, &test_list.list, list)
	{
		printf("ukey_name:[%s]\n" ,lt->str);
	}  

	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值