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 <stdio.h>
#include <stdlib.h>
#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<NUM_OF_TESTEXAMPLE; i++)
            {
                /* If match,then run the example code */
                if(cmd == testExample_st[i].sn)
                {
                    found = 1;
                    testExample_st[i].RunExample();
                }
            }
            /* If not found CMD in list, print a message */
            if(!found)
            {
                printf("Please select a valid test item for 1 to 9,print q to exit!Please:");
            }
        }
    }
    printf("Please press any key to exit the miniC project!");
    getchar();
    return 0;
}

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容