自己写的一些基础的C函数,如发现问题请不吝赐教。
一、循环队列。
注意对队列的任何操作都应该在list_lock_begin和list_lock_end之间。
1.1 循环队列结构体定义。
index - 下一个数据append时的索引;shift - 队列填满并开始“旋转”之后最旧的那个数据的索引。
typedef int32_t y_t;
typedef uint64_t x_t;
typedef struct {
x_t x;
y_t y;
} XYDATA;
typedef struct {
XYDATA *buf;
volatile uint8_t changed;
volatile uint8_t locked;
volatile uint8_t cleared;
uint32_t cnt; //data count now
uint32_t index; //index now
uint32_t shift; //shift count now
uint32_t TOTAL; //total data count of this list can hold
} DataListTypeDef;
1.2 初始化。为循环队列的buffer申请空间,并初始化结构体其他元素。
输入 :dl - 要初始化的循环队列指针;total - 循环队列元素总个数;
输出:无;
void list_init(DataListTypeDef *dl, uint32_t total) {
if (dl->buf == NULL) {
dl->buf = (XYDATA*)malloc((total) * sizeof(XYDATA));
}
else {
if (dl->TOTAL != total) {
dl->buf = (XYDATA*)realloc(dl->buf, dl->TOTAL * sizeof(XYDATA));
}
}
dl->locked = 0;
dl->TOTAL = total;
list_clear(dl);
dl->changed = 0;
dl->cleared = 0;
}
1.3 删除队列。释放buffer内存,并复位其他元素为默认值。
输入:dl - 队列指针;
输出:无;
void list_deinit(DataListTypeDef *dl) {
if (dl->buf != NULL) {
free(dl->buf);
dl->buf = NULL;
}
dl->TOTAL = 0;
dl->changed = 0;
}
1.4 队列追加一个新元素。
输入:dl - 队列指针;element - 新元素地址;
输出:无;
void list_append(DataListTypeDef *dl, XYDATA *element) {
memcpy(&(dl->buf[dl->index]), element, sizeof(XYDATA));
if (dl->cnt < dl->TOTAL) {
dl->cnt++; //modify count
dl->index++;
if (dl->index == dl->TOTAL) { //it is full just now
dl->index = 0;
}
} else { //it is full
if (dl->index < dl->TOTAL - 1) {
dl->index++;
} else {
dl->index = 0;
}
if (dl->shift < dl->TOTAL - 1) {
dl->shift++;
} else {
dl->shift = 0;
}
}
dl->changed = 1;
}
1.5 向队列追加一个子队列,同时子队列被清空。
输入:dl - 源队列指针;dl_extra - 子队列地址;
void list_append_list(DataListTypeDef *dl, DataListTypeDef *dl_extra) {
XYDATA *xy_pop;
while (!list_is_empty(dl_extra)) {
xy_pop = list_shift(dl_extra);
memcpy(&(dl->buf[dl->index]), xy_pop, sizeof(XYDATA));
if (dl->cnt < dl->TOTAL) {
dl->cnt++; //modify count
dl->index++;
if (dl->index == dl->TOTAL) { //it is full just now
dl->index = 0;
dl->shift = 1;
}
} else { //it is full
if (dl->index < dl->TOTAL - 1) {
dl->index++;
} else {
dl->index = 0;
}
if (dl->shift < dl->TOTAL - 1) {
dl->shift++;
} else {
dl->shift = 0;
}
}
}
dl->changed = 1;
}
1.6 获取指定索引的元素。
输入:dl - 队列指针;
输出:获取的元素的指针;
XYDATA* list_at(const DataListTypeDef *dl, uint32_t _index) {
if (_index + dl->shift < dl->TOTAL) {
return &(dl->buf[_index + dl->shift]);
} else {
return &(dl->buf[_index + dl->shift - dl->TOTAL]);
}
}
1.7 获取队列中最后一个元素。
输入:dl - 队列指针;
输出:获取的元素的指针;
XYDATA* list_last(const DataListTypeDef *dl) {
if (dl->index > 0) {
return &(dl->buf[dl->index - 1]);
} else {
return &(dl->buf[dl->TOTAL - 1]);
}
}
1.8 删除队列中的第一个元素并返回该元素的指针。
输入:dl - 队列指针;
输出:获取的元素的指针;
XYDATA *list_shift(DataListTypeDef *dl) {
if (dl->cnt == 0) {
return NULL;
}
XYDATA *xy_data = &(dl->buf[dl->shift]);
dl->shift++;
if (dl->shift == dl->TOTAL) {
dl->shift = 0;
}
dl->cnt--;
dl->changed = 1;
return xy_data;
}
1.9 清除队列。实际上不清除数据buffer,只是修改结构体变量。
void list_clear(DataListTypeDef *dl) {
dl->cnt = 0;
dl->index = 0;
dl->shift = 0;
dl->changed = 1;
dl->cleared = 1;
}
1.10 队列上锁。这里使用sleep_ms(1)函数避免可能造成的CPU占用过高,可以根据具体场合进行修改。
void list_lock_begin(DataListTypeDef *dl) {
while (dl->locked) {
sleep_ms(1);
}
dl->locked = 1;
}
1.11 队列解锁。
void list_lock_end(DataListTypeDef *dl) {
dl->locked = 0;
}
1.12 判断队列是否为空。
uint8_t list_is_empty(const DataListTypeDef *dl) {
return dl->cnt == 0;
}
1.13 判断队列是否已满。
uint8_t list_is_full(const DataListTypeDef *dl) {
return dl->cnt == dl->TOTAL;
}
1.14 获取队列当前元素数量。
uint32_t list_count(const DataListTypeDef *dl) {
return dl->cnt;
}
1.15 清除脏标志。
void list_clear_change_flag(DataListTypeDef *dl) {
dl->changed = 0;
}
1.16 获取脏标志。
uint8_t list_get_change_flag(const DataListTypeDef *dl) {
return dl->changed;
}
二、FIFO。
FIFO结构体定义。注意buf这里用了char*而没有用void*,是为了计算索引位置时方便。
ipp - 数据push索引;opp - 数据pop索引;
typedef struct {
char *buf;
uint16_t locked;
uint16_t ele_size;
uint32_t ipp;
uint32_t opp;
uint32_t depth;
} FifoListTypeDef;
2.1 初始化。
输入:stu - FIFO指针;ele_size - buf中一个数据所占用的字节数;realloc_cnt - buf可存储的最大数据个数;
输出:无;
void fifo_init(FifoListTypeDef *stu, int ele_size, uint32_t realloc_cnt) {
stu->ele_size = ele_size;
stu->ipp = 0;
stu->opp = 0;
stu->locked = 0;
stu->depth = realloc_cnt;
stu->buf = (char*)malloc(stu->depth * stu->ele_size);
}
2.2 删除FIFO。释放buf空间,并初始化结构体中的其他变量。
fifo_deinit(FifoListTypeDef *stu) {
if (stu->buf != NULL) {
free(stu->buf);
stu->buf = NULL;
}
stu->ipp = 0;
stu->opp = 0;
}
2.3 批量添加新数据。这里使用sleep_ms(1)函数避免可能造成的CPU占用过高,可以根据具体场合进行修改。
输入:stu - fifo指针;ele_arr - 数据数组指针;cnt - 要push的数据个数;
输出:无。
void fifo_in(FifoListTypeDef *stu, void* ele_arr, uint32_t cnt) {
while (stu->locked == 2) { //fifo clearing
sleep_ms(1);
}
stu->locked = 1;
if (stu->ipp < stu->opp) {
if (stu->ipp + cnt >= stu->opp) { //no enough memory
stu->locked = 0;
return;
}
}
else if (cnt >= stu->depth - stu->ipp + stu->opp) { //no enough memory
stu->locked = 0;
return;
}
if (stu->ele_size == 1) {
if (stu->ipp + cnt <= stu->depth) { //one part
memcpy(stu->buf + stu->ipp, ele_arr, cnt);
} else { //two parts
uint32_t cnt_part1 = stu->depth - stu->ipp;
memcpy(stu->buf + stu->ipp, ele_arr, cnt_part1);
memcpy(stu->buf, (char*)ele_arr + cnt_part1, cnt - cnt_part1);
}
} else {
if (stu->ipp + cnt <= stu->depth) { //one part
memcpy(stu->buf + stu->ele_size * stu->ipp, ele_arr, stu->ele_size * cnt);
} else { //two parts
uint32_t cnt_part1 = stu->depth - stu->ipp;
memcpy(stu->buf + stu->ele_size * stu->ipp, ele_arr, stu->ele_size * cnt_part1);
memcpy(stu->buf, (char*)ele_arr + stu->ele_size * cnt_part1, stu->ele_size * (cnt - cnt_part1));
}
}
stu->ipp = (stu->ipp + cnt)%stu->depth;
stu->locked = 0;
}
2.4 取出FIFO中的第一个数据。sleep_ms(1)说明同上。
void* fifo_out(FifoListTypeDef *stu) {
while (stu->locked == 2) { //fifo clearing
sleep_ms(1);
}
stu->locked = 1;
char* tmp;
if (stu->opp == stu->ipp) { //empty
stu->locked = 0;
return NULL;
}
tmp = stu->buf + stu->ele_size * stu->opp;
stu->opp = (stu->opp + 1)%stu->depth;
stu->locked = 0;
return tmp;
}
2.5 取出FIFO中前4个字节数据(double word)。sleep_ms(1)说明同上。
输入:stu - fifo指针;p_data - 要存储的4字节buffer地址;
输出:无。
int fifo_out_dw(FifoListTypeDef *stu, char *p_data) {
while (stu->locked == 2) { //fifo clearing
sleep_ms(1);
}
stu->locked = 1;
int cnt = stu->ipp - stu->opp;
if (cnt < 0) {
cnt += stu->depth;
}
if (cnt > 3) {
*(int*)p_data = *(int*)(stu->buf + stu->opp);
stu->opp = (stu->opp + 4)%stu->depth;
stu->locked = 0;
return 4;
}
stu->locked = 0;
return 0;
}
2.6 清除fifo。实际上不清除数据buffer,只是修改结构体变量。
void fifo_clear(FifoListTypeDef *stu) {
while (stu->locked) {
sleep_ms(1);
}
stu->locked = 2;
stu->ipp = 0;
stu->opp = 0;
stu->locked = 0;
}
三、双向链表。
该双向链表结构如下图。其中head->prev指向tail,这样可以通过head快速找到tail,方便进行尾插节点。
节点数据结构定义如下。
typedef struct _linklist {
void *buf;
struct _linklist *prev;
struct _linklist *next;
} LinkListTypeDef;
3.1 链表初始化。
输入:pp_head - 指向链表头指针的指针。注意要修改的主体是指针本身,因此要传入二级指针。
输出:无。
void linklist_init(LinkListTypeDef **pp_head) {
*pp_head = NULL;
}
3.2 删除链表。释放所有节点空间。
void linklist_deinit(LinkListTypeDef **pp_head) {
LinkListTypeDef *p = (*pp_head);
LinkListTypeDef *p_next;
while (p != NULL) {
p_next = p->next;
free(p);
p = p_next;
}
*pp_head = NULL;
}
3.3 添加节点(尾插法)。注意:1)ele不是节点指针而只是节点的数据指针,也就是节点的buf,下同;2)malloc的节点数据指针只是指向ele指向的内存区域,而没有进行深拷贝,如果需要进行深拷贝请将buf也malloc一份(但要知道malloc空间大小)然后memcpy。
输入:pp_head - 指向头指针的指针;ele - 要添加的节点数据
void linklist_append(LinkListTypeDef **pp_head, void* ele) {
if (*pp_head == NULL) {
*pp_head = (LinkListTypeDef *)malloc(sizeof(LinkListTypeDef));
(*pp_head)->buf = ele;
(*pp_head)->prev = *pp_head; //NOTE: *pp_head->prev pointer to linklist tail
(*pp_head)->next=NULL;
return;
}
LinkListTypeDef *p_tail = (*pp_head)->prev; //it is linklist tail
p_tail->next = (LinkListTypeDef *)malloc(sizeof(LinkListTypeDef));
p_tail->next->buf = ele;
p_tail->next->prev = p_tail;
p_tail->next->next = NULL;
(*pp_head)->prev = p_tail->next; //NOTE
}
3.4 添加节点(任意位置)。
输入:pp_head - 指向头指针的指针;ele - 要添加的节点数据指针;ele_after - 要插入的位置处的节点数据指针(ele添加到ele_after原来的位置,ele_after后移成为ele->next);
输出:无。
void linklist_insert(LinkListTypeDef **pp_head, void* ele, void* ele_after) {
if (ele_after == NULL) {
linklist_append(pp_head, ele);
return;
}
LinkListTypeDef *p = (*pp_head);
while (p != NULL && p->buf != ele_after) {
p = p->next;
}
if (p == NULL) { //not find ele_after, so append ele to linklist end
linklist_append(pp_head, ele);
return;
}
LinkListTypeDef *p_prev = p->prev;
LinkListTypeDef *p_insert = (LinkListTypeDef *)malloc(sizeof(LinkListTypeDef));
p_insert->buf = ele;
p_insert->prev = p_prev;
p_insert->next = p;
p->prev = p_insert;
if (p != (*pp_head)) {
p_prev->next = p_insert;
}
}
3.5 删除数据ele对应的节点。
void linklist_remove(LinkListTypeDef **pp_head, void* ele) {
LinkListTypeDef *p = (*pp_head);
while (p != NULL && p->buf != ele) {
p = p->next;
}
if (p != NULL) { //find ele in linklist
LinkListTypeDef *p_prev = p->prev;
if (p != (*pp_head)) {
p_prev->next = p->next;
if (p->next != NULL) {
p->next->prev = p_prev;
} else { //linklist tail
(*pp_head)->prev = p->prev; //NOTE
}
} else { //p_head is just the element to delete
if (p->next != NULL) { //list count more than 1
p->next->prev = p_prev;
}
*pp_head = p->next;
}
free(p);
}
}