在Libev的源码中,用到了一种用C实现类似C++中继承的技巧,主要是用宏和结构体实现。

在Libev中,最关键的数据结构就是各种监视器,比如IO监视器,信号监视器等等。这些监视器的多数成员都是一样的,只有少部分成员为各自独有。这就非常类似于C++中继承的使用场景了。废话少说,代码如下(略有改动,某些宏做了展开):

# define EV_CB_DECLARE(type) void (*cb)(struct ev_loop *loop, struct type *w, int revents);

#define EV_WATCHER(type)                    \
int active; /* private */ \
int pending; /* private */ \
int priority; /* private */ \
void *data; /* rw */ \
EV_CB_DECLARE (type) /* private */ #define EV_WATCHER_LIST(type) \
EV_WATCHER (type) \
struct ev_watcher_list *next; /* private */ typedef struct ev_watcher
{
EV_WATCHER (ev_watcher)
} ev_watcher; typedef struct ev_watcher_list
{
EV_WATCHER_LIST (ev_watcher_list)
} ev_watcher_list; typedef struct ev_io
{
EV_WATCHER_LIST (ev_io)
int fd; /* ro */
int events; /* ro */
} ev_io; typedef struct ev_signal
{
EV_WATCHER_LIST (ev_signal)
int signum; /* ro */
} ev_signal;

ev_watcher是所有结构的“基类”,宏EV_WATCHER定义了它的所有成员。像IO监视器、信号监视器等是以链表的形式进行组织的,所以,在ev_watcher基类的基础上,定义了ev_watcher的子类ev_watcher_list,宏EV_WATCHER_LIST就定义了该基类的所有成员。

ev_io和ev_signal相当于ev_watcher_list的子类,它们的前5个成员于ev_watcher相同,前6个成员与ev_watcher_list相同。

上面的代码可能还不是太清楚,下面将上面代码中的所有宏都展开,代码如下:

# define EV_CB_DECLARE(type) void (*cb)(struct ev_loop *loop, struct type *w, int revents);

#define EV_WATCHER(type)                    \
int active; /* private */ \
int pending; /* private */ \
int priority; /* private */ \
void *data; /* rw */ \
EV_CB_DECLARE (type) /* private */ #define EV_WATCHER_LIST(type) \
int active; /* private */ \
int pending; /* private */ \
int priority; /* private */ \
void *data; /* rw */ \
EV_CB_DECLARE (type) /* private */ \
struct ev_watcher_list *next; /* private */ typedef struct ev_watcher
{
int active;
int pending;
int priority;
void *data;
EV_CB_DECLARE (ev_watcher)
} ev_watcher; typedef struct ev_watcher_list
{
int active;
int pending;
int priority;
void *data;
EV_CB_DECLARE (ev_watcher_list)
struct ev_watcher_list *next;
} ev_watcher_list; typedef struct ev_io
{
int active;
int pending;
int priority;
void *data;
EV_CB_DECLARE (ev_io)
struct ev_watcher_list *next; int fd; /* ro */
int events; /* ro */
} ev_io; typedef struct ev_signal
{
int active;
int pending;
int priority;
void *data;
EV_CB_DECLARE (ev_signal)
struct ev_watcher_list *next;
int signum;
} ev_signal;

下面是Libev中如何使用这些结构体的代码:

void ev_start (struct ev_loop *loop, ev_watcher* w, int active)
{
...
w->active = active;
...
} void wlist_add (ev_watcher_list **head, ev_watcher_list *elem)
{
elem->next = *head;
*head = elem;
} void ev_io_start (struct ev_loop *loop, ev_io *w)
{
...
ev_start (loop, (ev_watcher*)w, 1);
...
wlist_add (&anfds[fd].head, (ev_watcher_list *)w);
}

在ev_io_start函数中,w是指向ev_io结构的指针,使用ev_start函数设置其成员active时,将其强制转换成基类ev_watcher,在将其添加进链表时,又将其强制转化为ev_watcher_list类型。

下面的代码是模拟上面的方法,写出的例子代码:

typedef struct
{
char *color;
int weight;
}fruit; typedef struct fruitlist
{
char *color;
int weight;
struct fruitlist *next;
}fruitlist; typedef struct
{
char *color;
int weight;
struct fruitlist *next;
char *taste;
}apple; void setcolorweight(fruit *f, char *color, int weight)
{
f->color = color;
f->weight = weight;
} void putinlist(fruitlist **head, fruitlist *ele)
{
ele->next = *head;
*head = ele;
}
void testinherit()
{
fruitlist *head = NULL; apple ap1;
setcolorweight((fruit *)&ap1, "red", 2);
ap1.taste = "sweet";
putinlist(&head, (fruitlist *)&ap1); apple ap2;
setcolorweight((fruit *)&ap2, "yellow", 1);
ap2.taste = "sour";
putinlist(&head, (fruitlist *)&ap2); fruitlist *p = head;
while(p != NULL)
{
printf("color is %s, weight is %d\n", p->color, p->weight);
p = (fruitlist *)(p->next);
}
}

结果如下:

color is yellow, weight is 1

color is red, weight is 2

Libev源码分析01:Libev中的监视器结构(C结构体实现继承)的更多相关文章

  1. [转]Libev源码分析 -- 整体设计

    Libev源码分析 -- 整体设计 libev是Marc Lehmann用C写的高性能事件循环库.通过libev,可以灵活地把各种事件组织管理起来,如:时钟.io.信号等.libev在业界内也是广受好 ...

  2. 一个由正则表达式引发的血案 vs2017使用rdlc实现批量打印 vs2017使用rdlc [asp.net core 源码分析] 01 - Session SignalR sql for xml path用法 MemCahe C# 操作Excel图形——绘制、读取、隐藏、删除图形 IOC,DIP,DI,IoC容器

    1. 血案由来 近期我在为Lazada卖家中心做一个自助注册的项目,其中的shop name校验规则较为复杂,要求:1. 英文字母大小写2. 数字3. 越南文4. 一些特殊字符,如“&”,“- ...

  3. angular源码分析:angular中脏活累活的承担者之$interpolate

    一.首先抛出两个问题 问题一:在angular中我们绑定数据最基本的方式是用两个大括号将$scope的变量包裹起来,那么如果想将大括号换成其他什么符号,比如换成[{与}],可不可以呢,如果可以在哪里配 ...

  4. angular源码分析:angular中入境检察官$sce

    一.ng-bing-html指令问题 需求:我需要将一个变量$scope.x = '<a href="http://www.cnblogs.com/web2-developer/&qu ...

  5. angular源码分析:angular中各种常用函数,比较省代码的各种小技巧

    angular的工具函数 在angular的API文档中,在最前面就是讲的就是angular的工具函数,下面列出来 angular.bind //用户将函数和对象绑定在一起,返回一个新的函数 angu ...

  6. angular源码分析:angular中的依赖注入式如何实现的

    一.准备 angular的源码一份,我这里使用的是v1.4.7.源码的获取,请参考我另一篇博文:angular源码分析:angular源代码的获取与编译环境安装 二.什么是依赖注入 据我所知,依赖注入 ...

  7. NIO 源码分析(01) NIO 最简用法

    目录 一.服务端 二.客户端 NIO 源码分析(01) NIO 最简用法 Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) J ...

  8. openVswitch(OVS)源码分析之工作流程(哈希桶结构体的解释)

    这篇blog是专门解决前篇openVswitch(OVS)源码分析之工作流程(哈希桶结构体的疑惑)中提到的哈希桶结构flex_array结构体成员变量含义的问题. 引用下前篇blog中分析讨论得到的f ...

  9. Libev源码分析09:select突破处理描述符个数的限制

    众所周知,Linux下的多路复用函数select采用描述符集表示处理的描述符.描述符集的大小就是它所能处理的最大描述符限制.通常情况下该值为1024,等同于每个进程所能打开的描述符个数. 增大描述符集 ...

随机推荐

  1. JavaScript 中的多线程通信的方法

    在Html 5诞生之后,我们可以使用javascript来实现多线程处理.H5 新增了一个web workers api,使用这个API,用户可以很容易地创建在后台运行的线程,H5 中被称为workd ...

  2. curl应用大法

    curl -s -S -k --max-redirs 5 -m 60 --connect-timeout 60 -w  "\n\n%{time_namelookup}|%{time_conn ...

  3. cf round 480E The Number Games

    题意:给一棵树,点$i$的点权是$2^i$,你需要删掉$k$个点,使得剩下的点连通的情况下剩下的点权值和最大. $k \leq n \leq 10^6$ 如果考虑删哪些点,是不好考虑的,会出问题. 反 ...

  4. MYSQL监控工具--mytop

    https://mp.weixin.qq.com/s/1X_uZaajImRRmpAsdLsNGw mysql可以说如今最为流行的数据库了,虽然现在nosql的风头正盛.但我想很多公司重要的业务数据不 ...

  5. laravel微信自定义分享

    https://blog.csdn.net/weixin_41530218/article/details/80777036 今天接触到了微信分享,来记录一下自己所理解的一些逻辑,首先,我画了一个草图 ...

  6. 利用JDBC连接Oracle数据库(转)

    http://blog.csdn.net/wahaha1_/article/details/8512438 JDBC是Sun公司制定的一个可以用Java语言连接数据库的技术. 一.JDBC基础知识 J ...

  7. Error configuring application listener of class org.springframework.web.context.ContextLoaderListene 标签: tomcat

    今天敲完ssm框架,启动tomcat时报了这个错误.如图: SEVERE: Error configuring application listener of class org.springfram ...

  8. Timer和DispatcherTimer简单使用

    1. 设定计时器相关属性,使用委托方法处理事件触发 DispatcherTimer dispatcherTimer= new DispatcherTimer(); dispatcherTimer.Ti ...

  9. Hdu 1729 Nim博弈

    点击打开题目链接 之前没做过这题,因为学弟问到我如果来求该题的sg值,才做了这题. 首先, 是多堆Nim博弈毫无疑问,这题是往一个有固定容量的箱子里放石子,和从一堆石子里面拿出石子是一个道理. 和传统 ...

  10. 序列化类型为“System.Data.Entity.DynamicProxies..."对象时检测到循环引用

    这是因为EF外键引起的序列化问题. 解决方案: context.Configuration.ProxyCreationEnabled = false; 这里我用的是一个基类控制器用于被继承 返回EF实 ...