在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. tomcat的三种部署项目的方式

    1.直接将项目放在webapps目录下. 如果将项目直接打成WAR包,放在webapps目录下会自动解压 项目的文件夹名称就是项目的访问路径,也就是虚拟目录. 2.配置conf文件夹下的server. ...

  2. Nginx 编译设置模块执行顺序

    Nginx编译时,配置"--add-module=xxx"可以加入模块,当我们需要按照指定顺序来设置过滤模块执行顺序时,先配置的"--add-module=xxx&quo ...

  3. CSS Tools: Reset CSS

    样式初始化 /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 License: none (public domain) */ ...

  4. 媒体查询(media):设置PC端网页居中显示

    @media screen and (min-width: 768px){ body{ background-color: #EAEAEA; } #fater{ width: 640px; margi ...

  5. 【JZOJ5060】【GDOI2017第二轮模拟day1】公路建设 线段树+最小生成树

    题面 在Byteland一共有n 个城市,编号依次为1 到n,它们之间计划修建m条双向道路,其中修建第i 条道路的费用为ci. Byteasar作为Byteland 公路建设项目的总工程师,他决定选定 ...

  6. Keil新建工程步骤

    第一步:创建工程文件夹 1.新建一个文件夹,例如: 2.在文件夹下创建子文件夹: 文件夹说明: App:存放硬件控制程序: Libraries:存放固件库: Obj:存放生成的文件: Public:存 ...

  7. FZU 1576【计算几何/费马点】

    Oaiei居住在A城市,并且是这个城市建设的总设计师.最近有个问题一直困恼着他.A城市里有三个大型工厂,每个大型工厂每天都需要消耗大量的石油,现在城市里要建设一个石油中转站,从石油中转站到三个大型工厂 ...

  8. Thrift框架应用参考

    Thrift https://blog.csdn.net/aquester/article/details/48261609 https://www.cnblogs.com/liboBlog/p/60 ...

  9. JavaScript--漏写var却还能使用标签

    一个漏写var带来的问题: 这个是不标准的写法!不建议使用 但是效果还是出来了,为什么呢? 原因: https://zhidao.baidu.com/question/1637589020484843 ...

  10. cocos2dx3.0项目创建流程

    cocos2dx3.0不是beta,新增了wp项目创建的支持 但不知道为啥非beta版本号的tools文件夹中取消了project-creator,可能有更改吧 没有这个工具还挺麻烦.就自己手动创建c ...