通常我们设计设计链表都是将数据域放在里面,这样每次需要使用链表的时候都需要实现一个链表,然后重新实现它的相关操作,这里参考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

下载代码

通用双向链表的设计(参考Linux系统中的实现)的更多相关文章

  1. 常见linux系统中RPM包的通用命名规则

    本文重点说一下在常见的linux系统中,RPM包通用的命名规则. RPM包的一般格式为:name-version-arch.rpmname-version-arch.src.rpm 例:httpd-2 ...

  2. (转)浅谈 Linux 系统中的 SNMP Trap

    原文:https://www.ibm.com/developerworks/cn/linux/l-cn-snmp/index.html 简介 本文讲解 SNMP Trap,在介绍 Trap 概念之前, ...

  3. 在linux系统中安装VSCode(Visual Studio Code)

    在linux系统中安装VSCode(Visual Studio Code) 1.从官网下载压缩包(话说下载下来解压就直接可以运行了咧,都不需要make) 访问Visual Studio Code官网  ...

  4. 用户管理 之 在Linux系统中,批量添加用户的操作流程

    一.阅读此文件您需要掌握的基础知识: <Linux 用户(user)和用户组(group)管理概述><用户(user)和用户组(group)配置文件详解><Linux 用 ...

  5. 用户管理 之 Linux 系统中的超级权限的控制

    在Linux操作系统中,root的权限是最高的,也被称为超级权限的拥有者.普通用户无法执行的操作,root用户都能完成,所以也被称之为超级管理用户. 在系统中,每个文件.目录和进程,都归属于某一个用户 ...

  6. 获得Unix/Linux系统中的IP、MAC地址等信息

    获得Unix/Linux系统中的IP.MAC地址等信息 中高级  |  2010-07-13 16:03  |  分类:①C语言. Unix/Linux. 网络编程 ②手册  |  4,471 次阅读 ...

  7. 理解Linux系统中的load average(图文版)转

    一.什么是load average? linux系统中的Load对当前CPU工作量的度量 (WikiPedia: the system load is a measure of the amount ...

  8. Linux系统中常见文件系统格式

    Windows常用的分区格式有三种,分别是FAT16.FAT32.NTFS格式. 在Linux操作系统里有Ext2.Ext3.Linux swap和VFAT四种格式. FAT16: 作为一种文件名称, ...

  9. Linux系统中存储设备的两种表示方法

    转:https://blog.csdn.net/holybin/article/details/38637381 一.对于IDE接口的硬盘的两种表示方法: 1.IDE接口硬盘,对于整块硬盘的两种表示方 ...

随机推荐

  1. Android Studio调试工具总结

       前言:写代码不可避免有Bug.通常情况下除了日志最直接的调试手段就是debug.当我们的程序出现bug时,调试能够高速的找到bug. 进入调试状态.我们能够清晰的了解程序的整个运行过程,能够对内 ...

  2. 翻翻git之---有用的欢迎页开源库 AppIntro

    转载请注明出处:王亟亟的大牛之路 今天没有P1.直接进入正题 今天上的是一个帅帅的app滑动介绍页 . 为什么说帅? 作者对自己的内容是这么定义的 Make a cool intro for your ...

  3. Sql语言复习

    一.创建数据库 创建和打开数据库 注意一点:在新建数据库的时候,一般放置数据文件与日志文件的位置,需要提前建立文件夹,不然会报错. 一般主数据文件,我们以.mdf结尾,次数据文件用.ndf结尾.对于日 ...

  4. Solaris 目录与文件管理

    熟悉系统目录结构 掌握27个常用命令 掌握针对目录.文件的操作 掌握查找与文件内容的操作 一.命令 命令:内部命令(不依赖其他文件,可以直接执行)与外部命令 .他是用于实现某一类功能的指令或程序,其执 ...

  5. DM8168 unrecoverable error: OMX_ErrorBadParameter (0x80001005) [resolved]

    DM8168 custom board 成功启动系统之后想先測一下8168编解码功能,把开发包里的examples跑一遍.启动完毕后.连上HDMI显示,在starting Matrix GUI app ...

  6. hdu5387(2015多校8)--Clock(模拟)

    题目链接:点击打开链接 题目大意:给出一个时间,问在钟表上这个时间的时候.时针和分针的角度,时针和秒针的角度.分针和秒针的角度.假设不是整数以分数的形式输出. 假设依照最小的格来算,那么: 1s对于秒 ...

  7. Spark SQL之External DataSource外部数据源(二)源代码分析

    上周Spark1.2刚公布,周末在家没事,把这个特性给了解一下,顺便分析下源代码,看一看这个特性是怎样设计及实现的. /** Spark SQL源代码分析系列文章*/ (Ps: External Da ...

  8. Linux下查看系统CPU个数、核心数、线程数

    1.查看物理CPU个数 (env) root@vmware01:~# grep 'physical id' /proc/cpuinfo physical physical physical physi ...

  9. hdu1878欧拉回路(DFS+欧拉回路)

    欧拉回路 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  10. windows下的txt格式转换成linux下的TXT

    存在的问题是 多出一个方框或者黑格子 主要是因为bash 不能忽略windows的问题 用sed 命令来处理,分别是windows转linux,linux转windows sed -e 's/.$// ...