在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. 关系数据库理论 ch.6

    6.1 问题的提出 关系模式是一个5元组 R U,D,DOM,F U 属性 D 域 DOM 属性到域的映射 F 依赖 在本章中将关系模式看作 三元组 R U,D 属性-依赖 1NF 每一个分量是不可分 ...

  2. Hibernate_条件查询客户列表

    分析:通过名称查询 实现: 1.在list.jsp中修改 2.修改ListCustomerServlet 首先获取cust_name,增加条件:若不为空,则模糊搜索,再调用Service方法,结果放到 ...

  3. 关于memset的使用

    有些oj上的G++支持 cstdio的memset,有些则支持stdio.h中的memset(划掉) 这两个头文件关系比较复杂, 具体我也说不清...按照c++文档中的说法,stdio已经deprec ...

  4. bzoj 4521 [Cqoi2016]手机号码——数位dp

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4521 dfs真好用~ #include<iostream> #include&l ...

  5. Qt: error lnk1158 无法运行rc.exe

    解决办法:(依据自己的环境而定) 将C:\Program Files (x86)\Windows Kits\\bin\10.0.15063.0\x64 目录下的rc.exe 和rcdll.dll 复制 ...

  6. margin负值5种应用

    最近做的项目中经常会用到margin的负值,这里就总结一下关于margin负值的5种使用及相关bug的解决. 1. 在流动性布局中的应用 如WordPress的两栏式不固定布局就是使用margin负值 ...

  7. Codeforces Round #395 (Div. 2) A. Taymyr is calling you【数论/最小公倍数】

    A. Taymyr is calling you time limit per test 1 second memory limit per test 256 megabytes input stan ...

  8. Leetcode892.Surface Area of 3D Shapes三维形体的表面积

    在 N * N 的网格上,我们放置一些 1 * 1 * 1  的立方体. 每个值 v = grid[i][j] 表示 v 个正方体叠放在单元格 (i, j) 上. 返回结果形体的总表面积. 示例 1: ...

  9. 【水滴石穿】MyFirstRNDemo

    比较简单的项目 //index.js /** @format */ import {AppRegistry} from 'react-native'; //默认创建的类 import App from ...

  10. input 手机数字键盘

    要一点击提起数字键盘,安卓只要设置input的类型是number或tel, ios 需要 pattern="number"可以直接打开搜狗输入法的数字键盘,可以输入.和数字如果只能 ...