学过数据结构之后,就会知道,链表是一种常用的管理数据的方式,在操作系统当中最为常见,链表大概有以下几种:
1).单向非循环链表
2).单向循环链表
3).双向非循环链表
4).双向循环链表
5).内核链表
其中个人认为越往下的链表越高级,当然,高级不一定就适用,有些地方就是需要一个简单的链表,然后可以做到少消耗资源,比如通知链,就用的是单向链表,在实时操作系统中,比如UCOS里则用的是双向循环链表,有的时候会和哈希算法一起组成哈希链表来管理多任务,UCOS的源代码是开源的,代码写的很漂亮,想学好C语言,可以先看看UCOS的代码,里面有很多编程思想都是可以借鉴的,我以前做项目遇到的一些困难,上面都能提供一个比较好的借鉴解决方式.
好了回到主题,我们本次主要说的是内核链表,它比其它几种链表的架构思想要更好一些,主要是链表和数据是分离的,且具备双向循环链表的所有特征,可以说是青出于蓝,而胜于蓝吧.在EngPC中就用到了内核链表, 关于内核链表的讲解机制,请参考其他人的博客或者相关书籍,我这里直接就以编程的方式简单使用一下内核链表,主要是可以掌握一个基础.
本次通过做一个下面的任务,让大家认识内核链表的使用方法:
用内核链表实顺序递增存储若干自然数,比如输入一个整数10,则建立一个内核链表,里面的每个节点分别存放1,2,3,4,5,6,7,8,9,10,然后通过某些操作,将其重新排列成1,3,5,7,9,10,8,6,4,2,即奇数升序偶数降序,并在屏幕上打印出来。
下面是主文件代码(myapp.c):
/*
* 用内核链表实顺序递增存储若干自然数,比如输入一个整数10,
* 则建立一个内核链表,里面的每个节点分别存放1,2,3,4,5,
* 6,7,8,9,10,然后通过某些操作,将其重新排列成1,3,5,7,
* 9,10,8,6,4,2,即奇数升序偶数降序,并在屏幕上打印出来。
*/
#include "kernellist.h"
void doublelist_sort(double_pnode h);
int main(void)
{
double_pnode h;
doublelist_init(&h);
doublelist_create(h);
doublelist_sort(h);
return 0;
}
void doublelist_sort(double_pnode h)
{
double_pnode p,t;
p = list_entry(h->list.prev,double_node,list);
while(p != h){
if(p->data % 2 == 1){ //奇数
p = list_entry(p->list.prev,double_node,list);
}else{ //偶数
t = p;
p = list_entry(p->list.prev,double_node,list);
list_move_tail(&t->list,&h->list);
doublelist_show(h);
}
}
}
然后是任务函数处理代码(kernellist.c):
#include "kernellist.h"
//初始化
void doublelist_init(double_pnode * H)
{
*H = (double_pnode)malloc(sizeof(double_node));
if(NULL == *H){
perror("malloc");
exit(1);
}
INIT_LIST_HEAD(&(*H)->list);
}
//遍历
void doublelist_show(double_pnode h)
{
double_pnode p;
list_for_each_entry(p,&h->list,list)
printf("%d\t",p->data);
printf("\n");
}
void doublelist_create(double_pnode h)
{
int n,i;
double_pnode new;
printf("请输入内核链表长度:");
scanf("%d",&n);
for(i = 0; i < n; i++){
new = (double_pnode)malloc(sizeof(double_node));
if(NULL == new){
perror("malloc");
exit(1);
}
printf("请输入数据:");
scanf("%d",&new->data);
list_add_tail(&new->list,&h->list);
doublelist_show(h);
}
}
然后是任务函数头文件(kernellist.h):
#ifndef __KERNELLIST_H
#define __KERNELLIST_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "eng_list.h"
typedef int datatype;
typedef struct doublenode{
datatype data;
struct list_head list; //list为结构体变量,不能定义成指针
}double_node,*double_pnode;
//初始化
extern void doublelist_init(double_pnode * H);
//在h指向的结点后插入新结点new
extern void doublelist_insert(double_pnode h,double_pnode new);
//在h指向的结点前插入新结点new
extern void doublelist_insert_tail(double_pnode h,double_pnode new);
//删除当前结点p
extern void doublelist_del(double_pnode p);
//判断是否为空
extern bool doublelist_isempty(double_pnode h);
//遍历
extern void doublelist_show(double_pnode h);
extern void doublelist_create(double_pnode h);
#endif
然后就是内核链表的一些相关操作的头文件(eng_list.h):
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
struct list_head{
struct list_head *next,*prev;
};
#define LIST_POISON1 ((void *) 0x00100100 + 0)
#define LIST_POISON2 ((void *) 0x00200200 + 0)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
#ifndef CONFIG_DEBUG_LIST
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;
}
#else
extern void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next);
#endif
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
#ifndef CONFIG_DEBUG_LIST
static inline void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
#else
extern void __list_del_entry(struct list_head *entry);
extern void list_del(struct list_head *entry);
#endif
static inline void list_replace(struct list_head *old,
struct list_head *new)
{
new->next = old->next;
new->next->prev = new;
new->prev = old->prev;
new->prev->next = new;
}
static inline void list_replace_init(struct list_head *old,
struct list_head *new)
{
list_replace(old, new);
INIT_LIST_HEAD(old);
}
static inline void list_del_init(struct list_head *entry)
{
__list_del_entry(entry);
INIT_LIST_HEAD(entry);
}
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del_entry(list);
list_add(list, head);
}
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del_entry(list);
list_add_tail(list, head);
}
static inline int list_is_last(const struct list_head *list,
const struct list_head *head)
{
return list->next == head;
}
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
static inline int list_empty_careful(const struct list_head *head)
{
struct list_head *next = head->next;
return (next == head) && (next == head->prev);
}
static inline void list_rotate_left(struct list_head *head)
{
struct list_head *first;
if (!list_empty(head)) {
first = head->next;
list_move_tail(first, head);
}
}
static inline int list_is_singular(const struct list_head *head)
{
return !list_empty(head) && (head->next == head->prev);
}
static inline void __list_cut_position(struct list_head *list,
struct list_head *head, struct list_head *entry)
{
struct list_head *new_first = entry->next;
list->next = head->next;
list->next->prev = list;
list->prev = entry;
entry->next = list;
head->next = new_first;
new_first->prev = head;
}
static inline void list_cut_position(struct list_head *list,
struct list_head *head, struct list_head *entry)
{
if (list_empty(head))
return;
if (list_is_singular(head) &&
(head->next != entry && head != entry))
return;
if (entry == head)
INIT_LIST_HEAD(list);
else
__list_cut_position(list, head, entry);
}
static inline void __list_splice(const struct list_head *list,
struct list_head *prev,
struct list_head *next)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
first->prev = prev;
prev->next = first;
last->next = next;
next->prev = last;
}
static inline void list_splice(const struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head, head->next);
}
static inline void list_splice_tail(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head->prev, head);
}
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head, head->next);
INIT_LIST_HEAD(list);
}
}
static inline void list_splice_tail_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head->prev, head);
INIT_LIST_HEAD(list);
}
}
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define __list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); pos = pos->prev)
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#define list_for_each_prev_safe(pos, n, head) \
for (pos = (head)->prev, n = pos->prev; \
pos != (head); \
pos = n, n = pos->prev)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
#define list_prepare_entry(pos, head, member) \
((pos) ? : list_entry(head, typeof(*pos), member))
#define list_for_each_entry_continue(pos, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_continue_reverse(pos, head, member) \
for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
#define list_for_each_entry_from(pos, head, member) \
for (; &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_safe_continue(pos, n, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_safe_from(pos, n, head, member) \
for (n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
n = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
#define list_safe_reset_next(pos, n, member) \
n = list_entry(pos->member.next, typeof(*pos), member)
#endif
然后就是一个Makefile文件:
CC = gcc
CFLAGS = -Wall -g -O0
SRC1 = myapp.c kernellist.c
OBJ1 = myapp
$(OBJ1) : $(SRC1)
$(CC) $(CFLAGS) -o $@ $^
clean:
$(RM) $(OBJ1) .*.sw?
下面是执行后的效果: