UVGUI链表实现原理

@firestaradmin 2020年10月17日22:08:27

UVGUI 的链表实现原理


UVGUI的链表是参考LVGL GUI库写的,在此做一下记录。

一、数据结构分析

/** Dummy type to make handling easier*/
typedef uint8_t ug_ll_node_t;


/** Description of a linked list*/
typedef struct {
    uint32_t n_size;        /* node size in bytes */
    ug_ll_node_t * head;
    ug_ll_node_t * tail;
} ug_ll_t;

UVGUI 的链表通过结构体ug_ll_t 表示。

节点则是typedef uint8_t ug_ll_node_t 定义,这只是虚假类型,只是为了处理时更方便。而实际储存的节点类型如下:

/* in fact, the node type is as follows  */
/*
struct _ug_ll_node{
    uint8_t node[node_size];
    ug_ll_node_t * prev;
    ug_ll_node_t * next;
}
*/

UVGUI 的链表使用时,先声明一个链表变量,用于储存链表信息,每创建一个节点,都会申请相应大小的内存块用于储存节点(即链表节点大小是固定的等于节点数据大小)。

二、初始化

初始化函数,根据指定的节点大小来初始化一个链表。将链表的头节点指针和尾节点指针设为NULL,然后设置节点大小。

/**
 * Initialize linked list
 * @param ll_dsc pointer to ll_dsc variable
 * @param node_size the size of 1 node in bytes
 */
void _ug_ll_init(ug_ll_t * ll_p, uint32_t node_size)
{
    ll_p->head = NULL;
    ll_p->tail = NULL;

    /*Round the size up to 4*/
    node_size = (node_size + 3) & (~0x3);

    ll_p->n_size = node_size;
}

三、API

1|插入节点

/**
 * Add a new head to a linked list
 * @param ll_p pointer to linked list
 * @return pointer to the new head
 */
void * _ug_ll_ins_head(ug_ll_t * ll_p)
{
    ug_ll_node_t * n_new;

    n_new = ug_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);

    if(n_new != NULL) {
        node_set_prev(ll_p, n_new, NULL);       /*No prev. before the new head*/
        node_set_next(ll_p, n_new, ll_p->head); /*After new comes the old head*/

        if(ll_p->head != NULL) { /*If there is old head then before it goes the new*/
            node_set_prev(ll_p, ll_p->head, n_new);
        }

        ll_p->head = n_new;      /*Set the new head in the dsc.*/
        if(ll_p->tail == NULL) { /*If there is no tail (1. node) set the tail too*/
            ll_p->tail = n_new;
        }
    }

    return n_new;
}


/**
 * Insert a new node in front of the n_act node
 * @param ll_p pointer to linked list
 * @param n_act pointer a node
 * @return pointer to the new head
 */
void * _ug_ll_ins_prev(ug_ll_t * ll_p, void * n_act)
{
    ug_ll_node_t * n_new;

    if(NULL == ll_p || NULL == n_act) return NULL;

    if(_ug_ll_get_head(ll_p) == n_act) {
        n_new = _ug_ll_ins_head(ll_p);
        if(n_new == NULL) return NULL;
    }
    else {
        n_new = ug_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
        if(n_new == NULL) return NULL;

        ug_ll_node_t * n_prev;
        n_prev = _ug_ll_get_prev(ll_p, n_act);
        node_set_next(ll_p, n_prev, n_new);
        node_set_prev(ll_p, n_new, n_prev);
        node_set_prev(ll_p, n_act, n_new);
        node_set_next(ll_p, n_new, n_act);
    }

    return n_new;
}

/**
 * Add a new tail to a linked list
 * @param ll_p pointer to linked list
 * @return pointer to the new tail
 */
void * _ug_ll_ins_tail(ug_ll_t * ll_p)
{
    ug_ll_node_t * n_new;

    n_new = ug_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);

    if(n_new != NULL) {
        node_set_next(ll_p, n_new, NULL);       /*No next after the new tail*/
        node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is the old tail*/
        if(ll_p->tail != NULL) {                /*If there is old tail then the new comes after it*/
            node_set_next(ll_p, ll_p->tail, n_new);
        }

        ll_p->tail = n_new;      /*Set the new tail in the dsc.*/
        if(ll_p->head == NULL) { /*If there is no head (1. node) set the head too*/
            ll_p->head = n_new;
        }
    }

    return n_new;
}

上述为三个插入节点的函数,插入的位置不同而已。

其中LL_NODE_META_SIZE 宏定义为两个节点指针的大小,如下:

#define LL_NODE_META_SIZE (sizeof(ug_ll_node_t *) + sizeof(ug_ll_node_t *))

其中有两个辅助函数node_set_prev , node_set_next ,用来设置节点的指针,使其指向相应的节点。定义如下:

/**
 * Set the previous node pointer of a node
 * @param ll_p pointer to linked list
 * @param act pointer to a node which prev. node pointer should be set
 * @param prev pointer to a node which should be the previous node before 'act'
 */
static void node_set_prev(ug_ll_t * ll_p, ug_ll_node_t * act, ug_ll_node_t * prev)
{
    if(act == NULL) return; /*Can't set the prev node of `NULL`*/

    uint8_t * act8 = (uint8_t *) act;

    act8 += LL_PREV_P_OFFSET(ll_p);

    ug_ll_node_t ** act_node_p = (ug_ll_node_t **) act8;
    ug_ll_node_t ** prev_node_p = (ug_ll_node_t **) &prev;

    *act_node_p = *prev_node_p;
}

/**
 * Set the 'next node pointer' of a node
 * @param ll_p pointer to linked list
 * @param act pointer to a node which next node pointer should be set
 * @param next pointer to a node which should be the next node before 'act'
 */
static void node_set_next(ug_ll_t * ll_p, ug_ll_node_t * act, ug_ll_node_t * next)
{
    if(act == NULL) return; /*Can't set the next node of `NULL`*/
    uint8_t * act8 = (uint8_t *) act;

    act8 += LL_NEXT_P_OFFSET(ll_p);
    ug_ll_node_t ** act_node_p = (ug_ll_node_t **) act8;
    ug_ll_node_t ** next_node_p = (ug_ll_node_t **) &next;

    *act_node_p = *next_node_p;
}

上述有两个宏定义,是根据节点结构计算指针的位置,如下:

#define LL_PREV_P_OFFSET(ll_p) (ll_p->n_size)
#define LL_NEXT_P_OFFSET(ll_p) (ll_p->n_size + sizeof(ug_ll_node_t *))

2|删除节点

/**
 * Remove the node 'node_p' from 'll_p' linked list.
 * It does not free the the memory of node.
 * @param ll_p pointer to the linked list of 'node_p'
 * @param node_p pointer to node in 'll_p' linked list
 */
void _ug_ll_remove(ug_ll_t * ll_p, void * node_p)
{
    if(_ug_ll_get_head(ll_p) == node_p) {
        /*The new head will be the node after 'n_act'*/
        ll_p->head = _ug_ll_get_next(ll_p, node_p);
        if(ll_p->head == NULL) {
            ll_p->tail = NULL;
        }
        else {
            node_set_prev(ll_p, ll_p->head, NULL);
        }
    }
    else if(_ug_ll_get_tail(ll_p) == node_p) {
        /*The new tail will be the  node before 'n_act'*/
        ll_p->tail = _ug_ll_get_prev(ll_p, node_p);
        if(ll_p->tail == NULL) {
            ll_p->head = NULL;
        }
        else {
            node_set_next(ll_p, ll_p->tail, NULL);
        }
    }
    else {
        ug_ll_node_t * n_prev = _ug_ll_get_prev(ll_p, node_p);
        ug_ll_node_t * n_next = _ug_ll_get_next(ll_p, node_p);

        node_set_next(ll_p, n_prev, n_next);
        node_set_prev(ll_p, n_next, n_prev);
    }
}

/**
 * Remove and free all elements from a linked list. The list remain valid but become empty.
 * @param ll_p pointer to linked list
 */
void _ug_ll_clear(ug_ll_t * ll_p)
{
    void * i;
    void * i_next;

    i      = _ug_ll_get_head(ll_p);
    i_next = NULL;

    while(i != NULL) {
        i_next = _ug_ll_get_next(ll_p, i);

        _ug_ll_remove(ll_p, i);
        ug_mem_free(i);

        i = i_next;
    }
}

其他相关函数请看源码。

四、源码

File “ug_ll.h”

#ifndef __UG_LL_H__
#define __UG_LL_H__

#include "ug_type.h"

/**********************
 *      MACROS
 **********************/

#define _UG_LL_READ(list, i) for(i = _ug_ll_get_head(&list); i != NULL; i = _ug_ll_get_next(&list, i))

#define _UG_LL_READ_BACK(list, i) for(i = _ug_ll_get_tail(&list); i != NULL; i = _ug_ll_get_prev(&list, i))



/** Dummy type to make handling easier*/
typedef uint8_t ug_ll_node_t;
/* in fact, the node type is as follows  */
/*
struct _ug_ll_node{
    uint8_t node[node_size];
    ug_ll_node_t * prev;
    ug_ll_node_t * next;
}
*/

/** Description of a linked list*/
typedef struct {
    uint32_t n_size;        /* node size in bytes */
    ug_ll_node_t * head;
    ug_ll_node_t * tail;
} ug_ll_t;




/**********************
 * GLOBAL PROTOTYPES
 **********************/

/**
 * Initialize linked list
 * @param ll_dsc pointer to ll_dsc variable
 * @param node_size the size of 1 node in bytes
 */
void _ug_ll_init(ug_ll_t * ll_p, uint32_t node_size);

/**
 * Add a new head to a linked list
 * @param ll_p pointer to linked list
 * @return pointer to the new head
 */
void * _ug_ll_ins_head(ug_ll_t * ll_p);

/**
 * Insert a new node in front of the n_act node
 * @param ll_p pointer to linked list
 * @param n_act pointer a node
 * @return pointer to the new head
 */
void * _ug_ll_ins_prev(ug_ll_t * ll_p, void * n_act);

/**
 * Add a new tail to a linked list
 * @param ll_p pointer to linked list
 * @return pointer to the new tail
 */
void * _ug_ll_ins_tail(ug_ll_t * ll_p);

/**
 * Remove the node 'node_p' from 'll_p' linked list.
 * It does not free the the memory of node.
 * @param ll_p pointer to the linked list of 'node_p'
 * @param node_p pointer to node in 'll_p' linked list
 */
void _ug_ll_remove(ug_ll_t * ll_p, void * node_p);

/**
 * Remove and free all elements from a linked list. The list remain valid but become empty.
 * @param ll_p pointer to linked list
 */
void _ug_ll_clear(ug_ll_t * ll_p);

/**
 * Move a node to a new linked list
 * @param ll_ori_p pointer to the original (old) linked list
 * @param ll_new_p pointer to the new linked list
 * @param node pointer to a node
 * @param head true: be the head in the new list
 *             false be the head in the new list
 */
void _ug_ll_chg_list(ug_ll_t * ll_ori_p, ug_ll_t * ll_new_p, void * node, bool head);

/**
 * Return with head node of the linked list
 * @param ll_p pointer to linked list
 * @return pointer to the head of 'll_p'
 */
void * _ug_ll_get_head(const ug_ll_t * ll_p);

/**
 * Return with tail node of the linked list
 * @param ll_p pointer to linked list
 * @return pointer to the head of 'll_p'
 */
void * _ug_ll_get_tail(const ug_ll_t * ll_p);

/**
 * Return with the pointer of the next node after 'n_act'
 * @param ll_p pointer to linked list
 * @param n_act pointer a node
 * @return pointer to the next node
 */
void * _ug_ll_get_next(const ug_ll_t * ll_p, const void * n_act);

/**
 * Return with the pointer of the previous node after 'n_act'
 * @param ll_p pointer to linked list
 * @param n_act pointer a node
 * @return pointer to the previous node
 */
void * _ug_ll_get_prev(const ug_ll_t * ll_p, const void * n_act);

/**
 * Return the length of the linked list.
 * @param ll_p pointer to linked list
 * @return length of the linked list
 */
uint32_t _ug_ll_get_len(const ug_ll_t * ll_p);

/**
 * TODO
 * @param ll_p
 * @param n1_p
 * @param n2_p
void ug_ll_swap(ug_ll_t * ll_p, void * n1_p, void * n2_p);
 */

/**
 * Move a node before an other node in the same linked list
 * @param ll_p pointer to a linked list
 * @param n_act pointer to node to move
 * @param n_after pointer to a node which should be after `n_act`
 */
void _ug_ll_move_before(ug_ll_t * ll_p, void * n_act, void * n_after);

/**
 * Check if a linked list is empty
 * @param ll_p pointer to a linked list
 * @return true: the linked list is empty; false: not empty
 */
bool _ug_ll_is_empty(ug_ll_t * ll_p);


#endif // !__UG_LL_H__

File “ug_ll.c”

#include "ug_ll.h"
#include "ug_mem.h"
/*********************
 *      DEFINES
 *********************/
#define LL_NODE_META_SIZE (sizeof(ug_ll_node_t *) + sizeof(ug_ll_node_t *))
#define LL_PREV_P_OFFSET(ll_p) (ll_p->n_size)
#define LL_NEXT_P_OFFSET(ll_p) (ll_p->n_size + sizeof(ug_ll_node_t *))

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

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void node_set_prev(ug_ll_t * ll_p, ug_ll_node_t * act, ug_ll_node_t * prev);
static void node_set_next(ug_ll_t * ll_p, ug_ll_node_t * act, ug_ll_node_t * next);


/**
 * Initialize linked list
 * @param ll_dsc pointer to ll_dsc variable
 * @param node_size the size of 1 node in bytes
 */
void _ug_ll_init(ug_ll_t * ll_p, uint32_t node_size)
{
    ll_p->head = NULL;
    ll_p->tail = NULL;

    /*Round the size up to 4*/
    node_size = (node_size + 3) & (~0x3);

    ll_p->n_size = node_size;
}

/**
 * Add a new head to a linked list
 * @param ll_p pointer to linked list
 * @return pointer to the new head
 */
void * _ug_ll_ins_head(ug_ll_t * ll_p)
{
    ug_ll_node_t * n_new;

    n_new = ug_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);

    if(n_new != NULL) {
        node_set_prev(ll_p, n_new, NULL);       /*No prev. before the new head*/
        node_set_next(ll_p, n_new, ll_p->head); /*After new comes the old head*/

        if(ll_p->head != NULL) { /*If there is old head then before it goes the new*/
            node_set_prev(ll_p, ll_p->head, n_new);
        }

        ll_p->head = n_new;      /*Set the new head in the dsc.*/
        if(ll_p->tail == NULL) { /*If there is no tail (1. node) set the tail too*/
            ll_p->tail = n_new;
        }
    }

    return n_new;
}



/**
 * Insert a new node in front of the n_act node
 * @param ll_p pointer to linked list
 * @param n_act pointer a node
 * @return pointer to the new head
 */
void * _ug_ll_ins_prev(ug_ll_t * ll_p, void * n_act)
{
    ug_ll_node_t * n_new;

    if(NULL == ll_p || NULL == n_act) return NULL;

    if(_ug_ll_get_head(ll_p) == n_act) {
        n_new = _ug_ll_ins_head(ll_p);
        if(n_new == NULL) return NULL;
    }
    else {
        n_new = ug_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
        if(n_new == NULL) return NULL;

        ug_ll_node_t * n_prev;
        n_prev = _ug_ll_get_prev(ll_p, n_act);
        node_set_next(ll_p, n_prev, n_new);
        node_set_prev(ll_p, n_new, n_prev);
        node_set_prev(ll_p, n_act, n_new);
        node_set_next(ll_p, n_new, n_act);
    }

    return n_new;
}

/**
 * Add a new tail to a linked list
 * @param ll_p pointer to linked list
 * @return pointer to the new tail
 */
void * _ug_ll_ins_tail(ug_ll_t * ll_p)
{
    ug_ll_node_t * n_new;

    n_new = ug_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);

    if(n_new != NULL) {
        node_set_next(ll_p, n_new, NULL);       /*No next after the new tail*/
        node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is the old tail*/
        if(ll_p->tail != NULL) {                /*If there is old tail then the new comes after it*/
            node_set_next(ll_p, ll_p->tail, n_new);
        }

        ll_p->tail = n_new;      /*Set the new tail in the dsc.*/
        if(ll_p->head == NULL) { /*If there is no head (1. node) set the head too*/
            ll_p->head = n_new;
        }
    }

    return n_new;
}


/**
 * Remove the node 'node_p' from 'll_p' linked list.
 * It does not free the the memory of node.
 * @param ll_p pointer to the linked list of 'node_p'
 * @param node_p pointer to node in 'll_p' linked list
 */
void _ug_ll_remove(ug_ll_t * ll_p, void * node_p)
{
    if(_ug_ll_get_head(ll_p) == node_p) {
        /*The new head will be the node after 'n_act'*/
        ll_p->head = _ug_ll_get_next(ll_p, node_p);
        if(ll_p->head == NULL) {
            ll_p->tail = NULL;
        }
        else {
            node_set_prev(ll_p, ll_p->head, NULL);
        }
    }
    else if(_ug_ll_get_tail(ll_p) == node_p) {
        /*The new tail will be the  node before 'n_act'*/
        ll_p->tail = _ug_ll_get_prev(ll_p, node_p);
        if(ll_p->tail == NULL) {
            ll_p->head = NULL;
        }
        else {
            node_set_next(ll_p, ll_p->tail, NULL);
        }
    }
    else {
        ug_ll_node_t * n_prev = _ug_ll_get_prev(ll_p, node_p);
        ug_ll_node_t * n_next = _ug_ll_get_next(ll_p, node_p);

        node_set_next(ll_p, n_prev, n_next);
        node_set_prev(ll_p, n_next, n_prev);
    }
}

/**
 * Remove and free all elements from a linked list. The list remain valid but become empty.
 * @param ll_p pointer to linked list
 */
void _ug_ll_clear(ug_ll_t * ll_p)
{
    void * i;
    void * i_next;

    i      = _ug_ll_get_head(ll_p);
    i_next = NULL;

    while(i != NULL) {
        i_next = _ug_ll_get_next(ll_p, i);

        _ug_ll_remove(ll_p, i);
        ug_mem_free(i);

        i = i_next;
    }
}


/**
 * Move a node to a new linked list
 * @param ll_ori_p pointer to the original (old) linked list
 * @param ll_new_p pointer to the new linked list
 * @param node pointer to a node
 * @param head true: be the head in the new list
 *             false be the head in the new list
 */
void _ug_ll_chg_list(ug_ll_t * ll_ori_p, ug_ll_t * ll_new_p, void * node, bool head)
{
    _ug_ll_remove(ll_ori_p, node);

    if(head) {
        /*Set node as head*/
        node_set_prev(ll_new_p, node, NULL);
        node_set_next(ll_new_p, node, ll_new_p->head);

        if(ll_new_p->head != NULL) { /*If there is old head then before it goes the new*/
            node_set_prev(ll_new_p, ll_new_p->head, node);
        }

        ll_new_p->head = node;       /*Set the new head in the dsc.*/
        if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/
            ll_new_p->tail = node;
        }
    }
    else {
        /*Set node as tail*/
        node_set_prev(ll_new_p, node, ll_new_p->tail);
        node_set_next(ll_new_p, node, NULL);

        if(ll_new_p->tail != NULL) { /*If there is old tail then after it goes the new*/
            node_set_next(ll_new_p, ll_new_p->tail, node);
        }

        ll_new_p->tail = node;       /*Set the new tail in the dsc.*/
        if(ll_new_p->head == NULL) { /*If there is no head (first node) set the head too*/
            ll_new_p->head = node;
        }
    }
}

/**
 * Return with head node of the linked list
 * @param ll_p pointer to linked list
 * @return pointer to the head of 'll_p'
 */
void * _ug_ll_get_head(const ug_ll_t * ll_p)
{
    void * head = NULL;

    if(ll_p != NULL) {
        head = ll_p->head;
    }

    return head;
}

/**
 * Return with tail node of the linked list
 * @param ll_p pointer to linked list
 * @return pointer to the head of 'll_p'
 */
void * _ug_ll_get_tail(const ug_ll_t * ll_p)
{
    void * tail = NULL;

    if(ll_p != NULL) {
        tail = ll_p->tail;
    }

    return tail;
}

/**
 * Return with the pointer of the next node after 'n_act'
 * @param ll_p pointer to linked list
 * @param n_act pointer a node
 * @return pointer to the next node
 */
void * _ug_ll_get_next(const ug_ll_t * ll_p, const void * n_act)
{
    if(ll_p == NULL) return NULL;

    /* Pointer to the next node is stored in the end of this node.
     * Go there and return the address found there */
    const ug_ll_node_t * n_act_d = n_act;
    n_act_d += LL_NEXT_P_OFFSET(ll_p);
    return *((ug_ll_node_t **)n_act_d);
}

/**
 * Return with the pointer of the previous node after 'n_act'
 * @param ll_p pointer to linked list
 * @param n_act pointer a node
 * @return pointer to the previous node
 */
void * _ug_ll_get_prev(const ug_ll_t * ll_p, const void * n_act)
{
    if(ll_p == NULL) return NULL;

    /* Pointer to the prev. node is stored in the end of this node.
     * Go there and return the address found there */
    const ug_ll_node_t * n_act_d = n_act;
    n_act_d += LL_PREV_P_OFFSET(ll_p);
    return *((ug_ll_node_t **)n_act_d);
}

/**
 * Return the length of the linked list.
 * @param ll_p pointer to linked list
 * @return length of the linked list
 */
uint32_t _ug_ll_get_len(const ug_ll_t * ll_p)
{
    uint32_t len = 0;
    void * node;

    for(node = _ug_ll_get_head(ll_p); node != NULL; node = _ug_ll_get_next(ll_p, node)) {
        len++;
    }

    return len;
}


/**
 * Move a node before an other node in the same linked list
 * @param ll_p pointer to a linked list
 * @param n_act pointer to node to move
 * @param n_after pointer to a node which should be after `n_act`
 */
void _ug_ll_move_before(ug_ll_t * ll_p, void * n_act, void * n_after)
{
    if(n_act == n_after) return; /*Can't move before itself*/

    void * n_before;
    if(n_after != NULL)
        n_before = _ug_ll_get_prev(ll_p, n_after);
    else
        n_before = _ug_ll_get_tail(ll_p); /*if `n_after` is NULL `n_act` should be the new tail*/

    if(n_act == n_before) return; /*Already before `n_after`*/

    /*It's much easier to remove from the list and add again*/
    _ug_ll_remove(ll_p, n_act);

    /*Add again by setting the prev. and next nodes*/
    node_set_next(ll_p, n_before, n_act);
    node_set_prev(ll_p, n_act, n_before);
    node_set_prev(ll_p, n_after, n_act);
    node_set_next(ll_p, n_act, n_after);

    /*If `n_act` was moved before NULL then it become the new tail*/
    if(n_after == NULL) ll_p->tail = n_act;

    /*If `n_act` was moved before `NULL` then it's the new head*/
    if(n_before == NULL) ll_p->head = n_act;
}

/**
 * Check if a linked list is empty
 * @param ll_p pointer to a linked list
 * @return true: the linked list is empty; false: not empty
 */
bool _ug_ll_is_empty(ug_ll_t * ll_p)
{
    if(ll_p == NULL) return true;

    if(ll_p->head == NULL && ll_p->tail == NULL) return true;

    return false;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/**
 * Set the previous node pointer of a node
 * @param ll_p pointer to linked list
 * @param act pointer to a node which prev. node pointer should be set
 * @param prev pointer to a node which should be the previous node before 'act'
 */
static void node_set_prev(ug_ll_t * ll_p, ug_ll_node_t * act, ug_ll_node_t * prev)
{
    if(act == NULL) return; /*Can't set the prev node of `NULL`*/

    uint8_t * act8 = (uint8_t *) act;

    act8 += LL_PREV_P_OFFSET(ll_p);

    ug_ll_node_t ** act_node_p = (ug_ll_node_t **) act8;
    ug_ll_node_t ** prev_node_p = (ug_ll_node_t **) &prev;

    *act_node_p = *prev_node_p;
}

/**
 * Set the 'next node pointer' of a node
 * @param ll_p pointer to linked list
 * @param act pointer to a node which next node pointer should be set
 * @param next pointer to a node which should be the next node before 'act'
 */
static void node_set_next(ug_ll_t * ll_p, ug_ll_node_t * act, ug_ll_node_t * next)
{
    if(act == NULL) return; /*Can't set the next node of `NULL`*/
    uint8_t * act8 = (uint8_t *) act;

    act8 += LL_NEXT_P_OFFSET(ll_p);
    ug_ll_node_t ** act_node_p = (ug_ll_node_t **) act8;
    ug_ll_node_t ** next_node_p = (ug_ll_node_t **) &next;

    *act_node_p = *next_node_p;
}


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!