通用雙向連結串列的設計(參考Linux系統中的實現)

weixin_33763244發表於2018-03-30

通常我們設計設計連結串列都是將資料域放在裡面,這樣每次需要使用連結串列的時候都需要實現一個連結串列,然後重新實現它的相關操作,這裡參考Linux系統中的設計實現了一個通用的雙向連結串列,只需要在你的結構裡面有一個這個連結串列的域,就可以使用連結串列的相關操作了。

注意:這個通用的雙向連結串列是參考Linux系統中的實現,它使用了typeof這個功能,所以有些編譯器可能不支援。我是再Windows系統中使用MinGW下使用GCC編譯的。

////////////////////////////////////////////////////////////////////////////////////////

// list.h


#ifndef _list_h
#define _list_h

typedef struct _list_head {
    struct _list_head *prev,*next;
} list_head;

#define offsetof(TYPE,MEMBER) ( (size_t) &((TYPE*)0)->MEMBER )

#define container_of(ptr,type,member) ({\
    const typeof( ((type*)0)->member ) *__mptr = (ptr);\
    (type*)( (char*)__mptr - offsetof(type,member) );})

#define list_empty(head) ( head->next==0&&head->prev==0 )

/* get the member of list object
 * @ptr        pointer to list_head
 * @type    the type of container which contains list_head field
 * @memeber field name in the container
 * @return    return pointer to the container
 */
#define list_entry(ptr,type,member) container_of(ptr,type,member)

/* add a new node after `head`
 */
void list_add(list_head *head,list_head *node);

/* delete a node
 */
void list_del(list_head *node);

#endif

/////////////////////////////////////////////////////////

// list.c

#include "list.h"

/* add a new node after `head`
 */
void list_add(list_head *head,list_head *node) {
    if(list_empty(head)) {
        head->next = head;
        head->prev = head;
    }
    node->next = head->next;
    node->prev = head;
    head->next->prev = node;
    head->next = node;
}
/* delete a node
 */
void list_del(list_head *node) {
    node->prev->next = node->next;
    node->next->prev = node->prev;
}

///////////////////////////////////////////////////////////////////////////////

// test.c

#include <stdio.h>
#include <assert.h>
#include "list.h"

typedef struct _task {
    int id;
    list_head next;
} task;

#define task_next(t) ( container_of(t->next.next,task,next) )

void task_print(task *t) {
    printf("#%d -> ",t->id);
}

void task_foreach(task *head,void (*callback)(task *)) {
    task *p = head;
    do {
        callback(p);
        p = task_next(p);
    }
    while (p!=head);
}

// use task like a list
void test_list() {
    task t1={1,{0,0}},
        t2={2,{0,0}},
        t3={3,{0,0}},
        t4={4,{0,0}},
        t5={5,{0,0}};

    list_add(&t1.next,&t2.next);
    list_add(&t2.next,&t3.next);
    list_add(&t3.next,&t4.next);
    list_add(&t4.next,&t5.next);

    task_foreach(&t1,task_print);
}

int main(int argc, char *argv[]) {
    test_list();

    return 0;
}

編譯執行

    gcc test.c list.h list.c -o test
    .\test.exe

下載程式碼

相關文章