通用链表的创建
//通用链表结构体,只保留指针域
type struct List
{
struct List *prev;
struct List *next;
}List;
添加节点
//添加链表节点
void AddNode(List *oldNode,List *newNode)
{
newNode->next = oldNode->next;
newNode->prev = oldNode;
oldNode->next->prev = newNode;
oldNode->next = newNode;
}
创建业务类型结构体
单纯的通用链表是没有意义的,要结合业务类型
//业务数据
typedef struct TempHumiSensor
{
uint32_t id;
uint8_t humi;
float temp;
List list;//是type struct List类型所以不能指向业务数据结构体的首地址,只能指向业务数据结构中
list成员的首地址
}TempHumiSensor;
通用链表的初始化
通用链表把初始化分为两部分,指针域和数据域分开初始化,大大提高了通用性,用户可以根据自己的业务需求创建业务数据域。
static List *g_tempHumiHeader;//头节点不需要数据所以用通用类型,后面的节点就要用业务数据类型了
//链表初始化函数
void InitList(List *header)
{
header->next = header;
header->prev = header;
}
//业务相关代码
bool InitTempHumiSensor(void)
{
g_tempHumiHeader = (List *)malloc(sizeof(struct List));
if(g_tempHumiHeader == NULL)
{
return false;//申请失败返回false
}
InitList(g_tempHumiHeader);//申请成功初始化链表
return true;
}
通用链表的添加
/*
**添加链表节点函数
* @brief 将节点添加到已有节点的后面
* @param oldNode:已有节点
* @param newNode:待添加节点
* @return
*/
void AddNode(List *oldNode, List *newNode)
{
newNode->next = oldNode->next;
newNode->prev = oldNode;
oldNode->next->prev = newNode;
oldNode->next = newNode;
}
/*
**添加链表业务相关节点
* @brief 将节点添加到链表的尾部
* @param header:头节点
* @param node:待添加节点
* @return
*/
void AddNodeToTail(List *header, List *node)
{
AddNode(header->prev, node);
}
/*
* @brief 将节点添加到头节点的后面
* @param header:头节点
* @param node:待添加节点
* @return
*/
void AddNodeToHead(List *header, List *node)
{
AddNode(header, node);
}
检测业务数据函数
//业务数据采集函数
TempHumiSensor *FindTempHumiSensor(void)//业务数据结构体指针类型
{
TempHumiSensor *sensor = (TempHumiSensor *)malloc(sizeof(TempHumiSensor));//定义局部变量
申请动态内存
if (sensor == NULL)//判断申请成功还是失败
{
return NULL;//申请失败返回NULL,并退出函数
}
//申请成功,访问成员赋值
static uint8_t id = 100;
//实际应用时直接赋值传感器的读取数据
sensor->id = id;
id--;
sensor->humi = 40;
sensor->temp = 20.5f;
return sensor;
}
添加传感器函数
//添加传感器函数
void AddTempHumiSensor(TempHumiSensor *sensor)
{
AddNodeToTail(g_tempHumiHeader, &sensor->list);//直接调用链表添加函数,取sensor->list
}
通用链表遍历
通用链表数据块是由list成员串联起来的,它的next和prev指向的是业务数据结构体中list成员的首地址,所以需要根据list成员的首地址得到业务数据结构体的首地址,才能进行访问其它成员的数据。
通过结构体成员获取结构体首地址宏定义
/**
* @brief 获取结构体中成员的偏移量
* @param typeName: 结构体类型的名字
* @param memberName: 成员的名字
* @return 成员在结构体当中的偏移量
*/
#define OFFSET_OF(typeName, memberName) ((uint32_t)&((typeName *)0)->memberName)
/**
* @brief 获取结构体的首地址
* @param typeName: 结构体类型的名字
* @param memberName: 成员的名字
* @return 结构体的首地址
*/
#define CONTAINER_OF(pMember, typeName, memberName) \
((typeName *)((uint8_t *)pMember - OFFSET_OF(typeName, memberName)))
主函数
int main(void)
{
if(!InitTempHumiSensor())//判断业务代码申请失败
{
return -1;
}
return 0;
}