1.1 内核双向链表实现
list_head.c
#include "list_head.h"
void INIT_LIST_HEAD(struct list_head *list)//初始化通用链表
{
//前后级指针都指向本身
list->next=list;
list->prev=list;
}
void list_add(struct list_head *node,struct list_head *head)//插入节点
{
node->next=head->next;
node->prev=head;
head->next->prev=node;
head->next=node;
}
void list_add_tail(struct list_head *node,struct list_head *head)//尾插
{
node->next=head->prev;
node->prev=head;
head->prev->next=node;
head->prev=node;
}
void list_del(struct list_head *node)//删除节点
{
node->prev->next=node->next;
node->next->prev=node->prev;
}
list_head.h
#ifndef __LIST_HEAD_H__
#define __LIST_HEAD_H__
//通用链表节点类型 双向链表
struct list_head{
struct list_head *prev; //前级指针
struct list_head *next;//后级指针
};
void INIT_LIST_HEAD(struct list_head *list);//初始化通用链表
void list_add(struct list_head *node,struct list_head *head);//插入节点
void list_add_tail(struct list_head *node,struct list_head *head);//尾插
void list_del(struct list_head *node);//删除节点
/*遍历链表 依次为:从头节点的下一个节点开始遍历
* 从头节点的上一个节点开始遍历
*(以list_for_next_each为例理解:首先节点指针pos指向头节点的下一个节点,判断
pos是否指向头节点,不是的话就向后继续遍历)
*/
#define list_for_next_each(pos,head)\
for(pos=(head)->next;pos!=(head);pos=pos->next)
#define list_for_prev_each(pos,head)\
for(pos=(head)->prev;pos!=(head);pos=pos->prev)
//提取数据结构 ptr 是链接因子的指针 type是包含了链接因子的数据类型 member是链接因子成员名。注意:系统不同,指针类型占用的空间不同。
#define container_of(ptr,type,member)\
(type *)( (long int)ptr - (long int)(&((type *)0)->member) )
#endif
1.2 运用实例
stu.h
#ifndef __STU_H__
#define __STU_H__
#define N 32
#include "list_head.h"
struct STU{
struct list_head list;//链接因子,放在最前或最后
int id;
char name[N];
char pwd[N];
float score;
};
#endif
test.c
#include <stdio.h>
#include <stdlib.h>
#include "list_head.h"
#include "stu.h"
#define DBG_MSG(fmt, arg...) do { \
printf("[%s] [%-10s] [%-4d] " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##arg); \
} while(0)
int main(int argc, const char *argv[])
{
int i;
struct STU *stu;
struct STU *stup;
struct list_head *pos;
struct list_head stu_list;//学生表的首节点
stu=(struct STU *)malloc(sizeof(struct STU)*5); //分配节点空间
if(!stu)
{
perror("fail to malloc");
return -1;
}
//初始化通用链表
INIT_LIST_HEAD(&stu_list);
for(i=0;i<5;i++) //赋值学生信息
{
stu[i].id=i;
sprintf(stu[i].name,"stu%d",i);
sprintf(stu[i].pwd,"160%d",i);
stu[i].score=10*i;
list_add(&stu[i].list,&stu_list);//插入链表,头插法
//list_add_tail(&stu[i].list,&stu_list);//插入链表,尾插发
}
//遍历学生信息
list_for_next_each(pos,&stu_list)
{
stup=container_of(pos,struct STU,list);
printf("stu:id=%d,name=%s,pwd=%s,score=%f\n",\
stup->id,stup->name,stup->pwd,stup->score);
}
puts("--------------------------------");
list_for_prev_each(pos,&stu_list)
{
stup=container_of(pos,struct STU,list);
//stup=(struct STU *)pos;//如果把通用链表放在结构体首部,则可以不用container_of
printf("stu:id=%d,name=%s,pwd=%s,score=%f\n",\
stup->id,stup->name,stup->pwd,stup->score);
}
return 0;
}
1.3 Makefile
######################################
#
######################################
#source file
#源文件,自动找所有.c和.cpp文件,并将目标定义为同名.o文件
SOURCE := $(wildcard *.c) $(wildcard *.cpp)
OBJS := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))
#target you can change test to what you want
#目标文件名,输入任意你想要的执行文件名
TARGET := test
#compile and lib parameter
#编译参数
CC := gcc
LIBS :=
LDFLAGS :=
DEFINES :=
INCLUDE := -I.
CFLAGS := -g -Wall -O3 $(DEFINES) $(INCLUDE)
CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H
#i think you should do anything here
#下面的基本上不需要做任何改动了
.PHONY : everything objs clean veryclean rebuild
everything : clean $(TARGET)
objs : $(OBJS)
rebuild: veryclean everything
clean :
@rm -fr *.so
@rm -fr *.o
veryclean : clean
@rm -fr $(TARGET)
$(TARGET) : $(OBJS)
@$(CC) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)
@chmod +x $(TARGET)