目录
3.1.关于#ifdef __cplusplus extern "C"
先放上参考资料:https://blog.youkuaiyun.com/caicaiatnbu/category_9096319.html
就是跟着别人的解析,一步一步去看darknet的结构。顺道加深C的学习,努力学习中。。
[使用的是这个版本的 https://github.com/AlexeyAB/darknet,因为一直在更新]
1.list.h
定义了节点和列表,申明了操作函数。可以看到,这个list就是简单地链表操作
#ifndef LIST_H
#define LIST_H
//这里先构建两个结构:节点和列表
typedef struct node{
void *val;//空指针,存放当前节点的值
struct node *next;//当前节点的下一节点
struct node *prev;//当前节点的上一节点
} node;
typedef struct list{
int size;//当前链表的长度
node *front;//当前链表的第一个节点
node *back;//当前链表的最后一个节点
} list;
#ifdef __cplusplus
extern "C" {
#endif
//定义的函数操作
list *make_list();//初始化链表
int list_find(list *l, void *val);//查找链表
void list_insert(list *, void *);//插入链表
void **list_to_array(list *l);//存储链表到数组
//释放存储空间
void free_list_val(list *l);
void free_list(list *l);
void free_list_contents(list *l);
void free_list_contents_kvp(list *l);
#ifdef __cplusplus
}
#endif
#endif
2.list.c
PS:关于xmalloc函数,我以为是X-分配器中的一部分,所以做了注解,但是读到utils.c文件的时候,发现就是源码自己的一个开辟空间的函数,只是多了一个判断而已。附上代码:
xmalloc函数:
//malloc构建size大小的存储空间
void *xmalloc(size_t size) {
void *ptr=malloc(size);
if(!ptr) {
malloc_error();
}
return ptr;
}
//calloc构建size大小的存储空间
void *xcalloc(size_t nmemb, size_t size) {
void *ptr=calloc(nmemb,size);
if(!ptr) {
calloc_error();
}
return ptr;
}
继续说我们今天看的list.c
#include <stdlib.h>
#include <string.h>
#include "list.h"
#include "utils.h"
#include "option_list.h"
//1.初始化链表
list *make_list()
{
list* l = (list*)xmalloc(sizeof(list));//分配链表的存储空间
l->size = 0;//链表长度
l->front = 0;//链表的头指针
l->back = 0;//链表的尾指针
return l;//返回初始化的链表
}
/*
void transfer_node(list *s, list *d, node *n)
{
node *prev, *next;
prev = n->prev;
next = n->next;
if(prev) prev->next = next;
if(next) next->prev = prev;
--s->size;
if(s->front == n) s->front = next;
if(s->back == n) s->back = prev;
}
*/
//删除链表最后一个节点
void *list_pop(list *l){
if(!l->back) return 0;//如果链表的最后一个节点为null,返回0.【!l->back这里表示链表为空】
//如果链表最后一个节点存在,链表不为空
node *b = l->back;//中间节点b指向链表最后一个节点
void *val = b->val;//获取最后一个节点的值
l->back = b->prev;//将链表的最后一个节点指向b的上一个节点,也就是原链表的倒数第二个节点
if(l->back) l->back->next = 0;//将链表尾指针的next节点设为null【切断原链表倒数第一个节点和倒数第二个节点的联系】
free(b);//释放中间节点的存储空间
--l->size;//将链表长度减一
return val;//返回删除节点的值
}
//链表的插入操作,按顺序插在最末
void list_insert(list *l, void *val)
{
node* newnode = (node*)xmalloc(sizeof(node));//首先创建一个待被插入的节点newnode
newnode->val = val;//赋值
newnode->next = 0;//因为是最末节点,所以nextnode=null
if(!l->back){//如果当前链表为空
l->front = newnode;//链表的头节点==newnode
newnode->prev = 0;//newnode的上一节点也应该是null
}else{//如果不为空
l->back->next = newnode;//链表的最后节点的next节点就为待插入的节点
newnode->prev = l->back;//newnode的上一节点应该是链表之前的最后节点
}
l->back = newnode;//新链表的最后节点,无论是什么情况,都应该是插入的节点
++l->size;//链表长度加一
}
//下面都是释放空间的操作
//释放节点空间,从传入节点n开始,后面的节点空间全部释放
void free_node(node *n)
{
node *next;
while(n) {
next = n->next;//获取下一释放节点
free(n);//释放当前节点
n = next;//循环更新
}
}
//释放链表的值空间,从链表头结点开始,全部释放
void free_list_val(list *l)
{
node *n = l->front;
node *next;
while (n) {
next = n->next;
free(n->val);
n = next;
}
}
//释放整个链表l的存储空间
void free_list(list *l)
{
free_node(l->front);//从节点开始释放链表
free(l);//释放链表空间
}
//不是跟free_list_val相似吗
void free_list_contents(list *l)
{
node *n = l->front;
while(n){
free(n->val);
n = n->next;
}
}
//这里突然有一个结构体kvp,被定义在"option_list.h"头文件中
/*
是用来提取.cfg文件中的关键字的
typedef struct{
char *key;
char *val;
int used;
} kvp;
*/
//也是释放空间,具体是什么操作,等我往后面看
void free_list_contents_kvp(list *l)
{
node *n = l->front;
while (n) {
kvp* p = (kvp*)n->val;
free(p->key);
free(n->val);
n = n->next;
}
}
//将链表中所有的节点进行保存
// 因为每个节点里保存的值是void类型的指针,故指针的指针,即二维指针【?】
void **list_to_array(list *l)
{
// 分配存储空间, 长度l-size, 每个空间大小为一个void类型指针
void** a = (void**)xcalloc(l->size, sizeof(void*));
int count = 0;
node *n = l->front;//从链表初始节点开始
while(n){
a[count++] = n->val;//存放值(void*型)
n = n->next;//更新循环
}
return a;
}
3.额外的知识
3.1.关于#ifdef __cplusplus extern "C"
关键字:extern "C" 表示编译生成的内部符号名使用C约定。
#ifdef __cplusplus
extern "C" {
#endif
// 代码
#ifdef __cplusplus
}
#endif
这个代码的意思是【参考:https://www.cnblogs.com/nx520zj/p/5920782.html】:
为了在C++代码中调用用C写成的库文件,就需要用extern"C"来告诉编译器:这是一个用C写成的库文件,请用C的方式来链接它们。两者语言的编译规则不一样。编译器对函数名的处理方法也不一样。
在C++中支持函数重载,而C中是不支持函数重载的。
3.2 xmalloc
【参考:https://www.oschina.net/translate/replace-malloc-free-with-a-fast-fixed-block-memory?print】
参考文献中说:X-分配器的基石,替换系统的malloc()和free()函数。
和大部分固定块分配器不同,X-分配器可以在预先不知道块大小和数量的前提下,以完全动态的方式运行。X-分配器也会为你提供所有的固定块管理方式。完美运行在任何PC或嵌入式设备上。此外,它还提供了内存的动态使用图可用于内存使用情况的统计。
如果你有一个应用程序真的需要反复申请堆内存,并引起了性能问题,或者你担心程序中的堆碎片问题,把 Allocator/xallocator 整合到你的程序里可能会解决这些问题。