C工程框架_学以致用--Apple的学习笔记

一,前言

从今天开始我准备进行一轮数据结构相关的C语言设计复习。原因是看代码的时候发现数据结构每个工程都有,然后都用自己的方式进行了封装,做成基础API供调用。而我平时很少去造轮子,但是最近看了linux+qemu+littlevgl+nuttxOS源码后,发现他们关于链表的具体设计的都不太一样,但是总体的抽象封装做的都很好。另外,他们的代码结构分层做的都很好,移植性和模块可扩展性都很好。为了将来也做一个开源大型工程,参考优秀开源代码的设计思路后,我现在要开始准备自己的轮子了。学以致用乐趣无穷。

二,代码框架

image.png

当前我用的是比较简单的输入输出系统,一个main中循环等待输入的待运行的example号,然后通过列表跳转法进入example子系统。example子系统中可以添加各个独立的小的example,比如我已经添加了2个单链表的example,main函数的列表中若添加了example子系统中的函数,则输入数字后,可以运行。这样的example子系统配置方式我是参考了littlevgl的设计,感觉不错,example文件夹可以不断的扩展c代码,只要添加到main.c数组testExample_st中就可以了。然后就是copy了lvgl中的log系统,就是一个c和一个h文件,做debug输出用。框架图如下,example子自动中可以不断扩展,今天做的是2个单链表的例子。
main.c源码

/******************************************************************************
Project                      : MiniC
Description                  : MiniC project
CPU and Compiler             : win10 codeblocks mingw32
Author                       : AppleCai
Date                         : 2020-04-23
*******************************************************************************/
/*********************
 *      INCLUDES
 *********************/
#include 
#include 
#include "main.h"
/**********************
 *      MACROS
 **********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
*     GLOBAL VAR
**********************/

/**********************
 *     CONST VAR
 **********************/
const example testExample_st[NUM_OF_TESTEXAMPLE]=
{
    {'1',slist},  /* test1.c */
    {'2',slist2}, /* test2.c */
};
/**********************
 * Functions Implement
 **********************/

int main()
{
    char cmd;
    int i = 0;
    unsigned char found=0;
    printf("**************************************************************\n");
    printf("****Welcome to miniC V1.0.0 project! Copyright by AppleCai****\n");
    printf("**************************************************************\n");
    printf("Please select test item[1-9],print q to exit!Please:");
    while (scanf("%c",&cmd))
    {
        getchar(); //clear \n
        if (cmd=='q')
        {
            printf("Bye Apple Cai!\n");
            break;
        }
        else
        {
            found = 0;
            for(i=0; i

三,test1中精华说明

我花费时间看源码除了觉得好奇或者好玩外,我顺便还取其精华去其糟粕。那么让我印象深刻的就是可复用性,因为我看的代码中双链表都抽象的很好,但是我今天先做下单链表。单链表其实不怎么用的,他再查找方面比双链表效率低。我先不设计双链表的原因是怕自己变成完全copy开源代码了,所以单链表我最近看的开源代码中没有印象,那么用单链表全都是我自己设计出来的。另外,单纯的去用数据结构,那么就没有意思,稍微带点应用,所以我设计的了简单的借书系统,用c语言面向对象的思路去设计,主要围绕创建借书单来运用的。
关于test1.c中的单链表的创建head,插入(头插和尾插),删除,查找,遍历,还没有设计到抽象,主要是实现下,另外尝试下不同的接口传递,代码的实现方式也都是不同的。在test1.c中删除我用了3种方式去实现。REMOVE_FROM_SLIST中用了qemu之前看到的成员名称替代法,removeFromSlist的参数包括了成员,感觉复用性不好。removeFromSlist_2的参数都是node,复用性还是比较好的,这个类似于linux驱动的传参。

    printf("\n7) Return book ID 2!\n");
    removeFromSlist(booksystem,2);
    REMOVE_FROM_SLIST(booksystem,bookID,2);
    removeFromSlist_2(booksystem,customer2);
#define REMOVE_FROM_SLIST(head,elem,item)  \
    sl *p = head;  \
    sl *n = p->next;  \
    uint8 found = 0;  \
    while(n)  \
    {  \
        if(n->elem == item)  \
        {  \
            found = 1;  \
            p->next = n->next;  \
            free(n);  \
            break;  \
        }  \
        p = n;  \
        n = n->next;  \
    }  \
    if(found == 0)  \
    {  \
        LOG_TRACE("Can't find Book ID!");  \
    }

/**
 * remove from list by node
 * @param head: head of single list
 * @param node: book id which to be delete from list
 */
void removeFromSlist(sl *head,uint8 bookid)
{
    /* Due to remove, so we shall save two point. */
    sl *p = head;
    sl *n = p->next;
    boolean found = 0;
    while(p)
    {
        if(n->bookID == bookid)
        {
            found = 1;
            printf("Book ID %d is returned for person ID 0x%X\n",n->bookID,n->personID);
            p->next = n->next;
            free(n);
            break;
        }
        p=n;
        n=n->next;
    }
    if(found == 0)
    {
        LOG_TRACE("Can't find Book ID!");
    }
    LOG_TRACE("Remove single list done!");
}
/**
 * remove from list by node
 * @param head: head of single list
 * @param node: node of list which to be delete from list
 */
void removeFromSlist_2(sl *head,sl *node)
{
    /* Due to remove, so we shall save two point. */
    sl *p = head;
    sl *n = p->next;
    boolean found = 0;
    while(n)
    {
        if(n == node)
        {
            found = 1;
            printf("Book ID %d is returned for person ID 0x%X\n",n->bookID,n->personID);
            p->next = n->next;
            free(n);
            break;
        }
        p=n;
        n=n->next;
    }
    if(found == 0)
    {
        LOG_TRACE("Can't find this node!");
    }
    LOG_TRACE("Remove single list done!");
}

三,test2中精华说明

重点介绍test2.c,对象结构体封装用了小链表方式。进行了数据和链表的隔离,并且小链表放在了结构体的第一个元素。另外就是对于对象的action仿照了linux驱动的注册钩子的方式。

typedef struct _sl
{
    struct _sl *next;
} sl_t;

typedef struct
{
    uint8 bookID;         /* book id */
    uint16 personID;      /* person id */
    boolean bookStatus;   /* 0:return 1:borrow */
} system_t;

typedef struct _booksystem_t
{
    sl_t sl;        /* shall be put in the top of struct */
    system_t obj;   /* obj */
    /* actions */
    void (*initbook)(struct _booksystem_t *);    
    void (*borrowbooks)(struct _booksystem_t *,struct _booksystem_t *);
    void (*returnbooks)(struct _booksystem_t * ,uint8 );
    void (*printborrowbooklist)(struct _booksystem_t *);
    void (*searchbooks)(struct _booksystem_t * ,uint8 );
} booksystem_t;
然后这些钩子函数注册的函数设计思路和test1是一样的。然后用钩子的灵活性就体现了,一开始注册是头插appleBooks->borrowbooks = insertSList_head;后来注册为尾插appleBooks->borrowbooks = insertSList_tail;
test2.c
```c
/******************************************************************************
Project                      : Single List
Description                  : create;insert;remove;search;traversal functions
CPU and Compiler             : win10 codeblocks mingw32
Author                       : AppleCai
Date                         : 2020-04-23
*******************************************************************************/
/*********************
 *      INCLUDES
 *********************/
#include 
#include 
#include "../typedef.h"
/**********************
 *      MACROS
 **********************/
//#define MAXNUM_OF_BOOKS  5
/* the status of borrow of book */
#define BOOKED           1
#define RETURNED         0
/**********************
 *      TYPEDEFS
 **********************/
typedef struct _sl
{
    struct _sl *next;
} sl_t;

typedef struct
{
    uint8 bookID;
    uint16 personID;
    boolean bookStatus;
} system_t;

typedef struct _booksystem_t
{
    sl_t sl;        /* shall be put in the top of struct */
    system_t obj;
    void (*initbook)(struct _booksystem_t *);
    void (*borrowbooks)(struct _booksystem_t *,struct _booksystem_t *);
    void (*returnbooks)(struct _booksystem_t * ,uint8 );
    void (*printborrowbooklist)(struct _booksystem_t *);
    void (*searchbooks)(struct _booksystem_t * ,uint8 );
} booksystem_t;
/**********************
 *     GLOBAL VAR
 **********************/

/**********************
 *     CONST VAR
 **********************/

/**********************
 * Functions Implement
 **********************/
void init_slist(booksystem_t * head)
{
    /* initlize head */
    booksystem_t *p = head;
    p->obj.bookID = 0;
    p->obj.bookStatus = RETURNED;
    p->obj.personID = 0;
    p->sl.next = NULL;
    #if 0
    /* initlize other nodes */
    uint8 i = 0;
    for (i = 0; i < MAXNUM_OF_BOOKS-1; i++)
    {
        booksystem_t *a=(booksystem_t*)malloc(sizeof(booksystem_t));
        a->obj.bookID = i+2;
        a->obj.bookStatus = RETURNED;
        a->obj.personID = 0;
        a->sl.next = NULL;
        p->sl.next = a;
        p=a;
    }
    #endif
    LOG_TRACE("init the head of single list done!");
}
void print_slist(booksystem_t * head)
{
    booksystem_t *p = (booksystem_t *)head->sl.next;
    while(p)
    {
        printf("Book ID %d borrowed for person ID 0x%X\n",p->obj.bookID,p->obj.personID);
        p = (booksystem_t *)p->sl.next;
    }
    LOG_TRACE("Traversal single list done!");
}

void insertSList_head(booksystem_t *head,booksystem_t *node)
{
    node->sl.next = head->sl.next;
    head->sl.next = (sl_t *)node;
    LOG_TRACE("head insert for single list done!");
}

void insertSList_tail(booksystem_t *head,booksystem_t *node)
{
    booksystem_t *p = head;
    /* find the last node when p->next is null */
    while(p->sl.next)
    {
        p = (booksystem_t *)p->sl.next;
    }
    /* change null to new node */
    p->sl.next = (sl_t *)node;
    node->sl.next = NULL;
    LOG_TRACE("tail insert for single list done!");
}

#define REMOVE_FROM_LIST(st,head,elem,item)  \
    st *p = head;  \
    st *n = (st *)p->sl.next;  \
    uint8 found = 0;  \
    while(n)  \
    {  \
        if(n->obj.elem == item)  \
        {  \
            found = 1;  \
            p->sl.next = n->sl.next;  \
            free(n);  \
            break;  \
        }  \
        p = n;  \
        n = (st *)n->sl.next;  \
    }  \
    if(found == 0)  \
    {  \
        LOG_TRACE("Can't find Book ID!");  \
    }

void removefromSlist(booksystem_t * head,uint8 item)
{
    REMOVE_FROM_LIST(booksystem_t,head,bookID,item);
}

void search_Slist(booksystem_t *head,uint8 bookid)
{
    booksystem_t *p = (booksystem_t *)head->sl.next;
    boolean found = 0;
    while(p)
    {
        if(p->obj.bookID == bookid)
        {
            found = 1;
            printf("Book ID %d is borrowed for person ID 0x%X\n",p->obj.bookID,p->obj.personID);
            break;
        }
        p = (booksystem_t *)p->sl.next;
    }
    if(found == 0)
    {
        printf("Nobody borrow book ID %d\n",bookid);
    }
    LOG_TRACE("Search single list done!");
}

/**
 * free list from head
 * @param head: head of single list
 */
void DeInitAll(booksystem_t * head)
{
    booksystem_t *p = head;
    booksystem_t *q;
    while(p)
    {
        q = (booksystem_t *)p->sl.next; /* save next */
        free(p);  /* free current point */
        p = q;    /* point to the next obj */
    }
}

void slist2(void)
{
    printf("you select Single list test example 2!\n");
    /*********** Init *****************************/
    booksystem_t *appleBooks; /* head */
    appleBooks = (booksystem_t *)malloc(sizeof(booksystem_t));
    appleBooks->initbook = init_slist;
    appleBooks->borrowbooks = insertSList_head;
    appleBooks->returnbooks = removefromSlist;
    appleBooks->printborrowbooklist = print_slist;
    appleBooks->searchbooks = search_Slist;
    /* initlize head */
    printf("\n1) Initlize Apple Book System!\n");
    if(appleBooks->initbook)
    {
        appleBooks->initbook(appleBooks);
    }
    /* insert node */
    printf("\n2) Three person borrow books!\n");
    if(appleBooks->borrowbooks)
    {
        uint8 i = 0;
        for (i = 0;i<3;i++)
        {
            booksystem_t *customer = (booksystem_t *)malloc(sizeof(booksystem_t));
            customer->obj.bookID = i+1;
            customer->obj.bookStatus = BOOKED;
            customer->obj.personID = 0x1001+i;
            customer->sl.next = NULL;
            appleBooks->borrowbooks(appleBooks,customer);
            printf("Book ID %d is borrowed for person ID 0x%X\n",customer->obj.bookID,customer->obj.personID);
        }
    }
    /* traversal */
    printf("\n3) Print borrow-list of booksystem!\n");
    if(appleBooks->printborrowbooklist)
    {
        appleBooks->printborrowbooklist(appleBooks);
    }
    /* search */
    printf("\n4) Check the status of book ID 2!\n");
    if(appleBooks->searchbooks)
    {
        appleBooks->searchbooks(appleBooks,2);
    }
    /* remove */
    printf("\n5) Return book ID 2!\n");
    if(appleBooks->returnbooks)
    {
        appleBooks->returnbooks(appleBooks,2);
    }
    printf("\n6) Print borrow-list of booksystem again!\n");
    if(appleBooks->printborrowbooklist)
    {
        appleBooks->printborrowbooklist(appleBooks);
    }
    /* insert tail */
    appleBooks->borrowbooks = insertSList_tail;
    printf("\n7) Next person borrow a book!\n");
    if(appleBooks->borrowbooks)
    {
        booksystem_t *customer = (booksystem_t *)malloc(sizeof(booksystem_t));
        customer->obj.bookID = 4;
        customer->obj.bookStatus = BOOKED;
        customer->obj.personID = 0x1004;
        customer->sl.next = NULL;
        appleBooks->borrowbooks(appleBooks,customer);
    }
    printf("\n8) Print borrow-list of booksystem again!\n");
    if(appleBooks->printborrowbooklist)
    {
        appleBooks->printborrowbooklist(appleBooks);
    }
    DeInitAll(appleBooks);
    /*********** End ******************************/
    printf("\nPlease select next test item[1-9],print q to exit!Please:");
}

四,运行结果

**************************************************************
****Welcome to miniC V1.0.0 project! Copyright by AppleCai****
**************************************************************
Please select test item[1-9],print q to exit!Please:1
you select Single list test example 1!
LOG:[initSlist: init single list done! (in test1.c line #48)]

1) The first person borrows a book!
Customer ID(0x1000),borrowed a book ID(1)
LOG:[insertList_head: head insert for single list done! (in test1.c line #55)]

2) The second person borrows a book!
Customer ID(0x1001),borrowed a book ID(2)
LOG:[insertList_head: head insert for single list done! (in test1.c line #55)]

3) The third person borrows a book!
Customer ID(0x1002),borrowed a book ID(3)
LOG:[insertList_head: head insert for single list done! (in test1.c line #55)]

4) Print borrow-list of bookSystem!
Book ID 3 borrowed for person ID 0x1002
Book ID 2 borrowed for person ID 0x1001
Book ID 1 borrowed for person ID 0x1000
LOG:[printAllSlist: Traversal single list done! (in test1.c line #88)]

5) Check the status of book ID 2!
Book ID 2 is borrowed for person ID 0x1001
LOG:[searchSlist: Search single list done! (in test1.c line #108)]

6) Check the status of book ID 4!
Nobody borrow book ID 4
LOG:[searchSlist: Search single list done! (in test1.c line #108)]

7) Return book ID 2!
Book ID 2 is returned for person ID 0x1001
LOG:[removeFromSlist: Remove single list done! (in test1.c line #153)]
LOG:[slist: Can't find Book ID! (in test1.c line #223)]
LOG:[removeFromSlist_2: Can't find this node! (in test1.c line #180)]
LOG:[removeFromSlist_2: Remove single list done! (in test1.c line #182)]

8) Print borrow-list of bookSystem again!
Book ID 3 borrowed for person ID 0x1002
Book ID 1 borrowed for person ID 0x1000
LOG:[printAllSlist: Traversal single list done! (in test1.c line #88)]

9) The fourth person borrows a book ID 2!
Customer ID(0x1004),borrowed a book ID(2)
LOG:[insertList_tail: tail insert for single list done! (in test1.c line #69)]

10) Print borrow-list of booksystem again!
Book ID 3 borrowed for person ID 0x1002
Book ID 1 borrowed for person ID 0x1000
Book ID 2 borrowed for person ID 0x1004
LOG:[printAllSlist: Traversal single list done! (in test1.c line #88)]

Please select next test item[1-9],print q to exit!Please:2
you select Single list test example 2!

1) Initlize Apple Book System!
LOG:[init_slist: init the head of single list done! (in test2.c line #79)]

2) Three person borrow books!
LOG:[insertSList_head: head insert for single list done! (in test2.c line #96)]
Book ID 1 is borrowed for person ID 0x1001
LOG:[insertSList_head: head insert for single list done! (in test2.c line #96)]
Book ID 2 is borrowed for person ID 0x1002
LOG:[insertSList_head: head insert for single list done! (in test2.c line #96)]
Book ID 3 is borrowed for person ID 0x1003

3) Print borrow-list of booksystem!
Book ID 3 borrowed for person ID 0x1003
Book ID 2 borrowed for person ID 0x1002
Book ID 1 borrowed for person ID 0x1001
LOG:[print_slist: Traversal single list done! (in test2.c line #89)]

4) Check the status of book ID 2!
Book ID 2 is borrowed for person ID 0x1002
LOG:[search_Slist: Search single list done! (in test2.c line #156)]

5) Return book ID 2!

6) Print borrow-list of booksystem again!
Book ID 3 borrowed for person ID 0x1003
Book ID 1 borrowed for person ID 0x1001
LOG:[print_slist: Traversal single list done! (in test2.c line #89)]

7) Next person borrow a book!
LOG:[insertSList_tail: tail insert for single list done! (in test2.c line #110)]

8) Print borrow-list of booksystem again!
Book ID 3 borrowed for person ID 0x1003
Book ID 1 borrowed for person ID 0x1001
Book ID 4 borrowed for person ID 0x1004
LOG:[print_slist: Traversal single list done! (in test2.c line #89)]

Please select next test item[1-9],print q to exit!Please:q
Bye Apple Cai!
Please press any key to exit the miniC project!

五,总结

学以致用乐趣无穷,为了我7年后的终极目标,现在就开始准备自己的库,顺便把基础知识再回顾下。完成后还是很有成就感的呢!我喜欢别人用我做的轮子,不喜欢用别人的轮子,因为在我思维里做轮子的是创造者,用轮子的会受到限制,只是使用者。其实用轮子的也可以二次开发,或者拿着轮子继续发明创造,只是我个人比较喜欢自己做轮子罢了。

你可能感兴趣的:(C工程框架_学以致用--Apple的学习笔记)