在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