libev源代码由于有各种宏定义,十分让人费解,作者这么写确实使得代码很简练,但也给读者的阅读带来了巨大的麻烦,下面将分析下ev_loop这个结构体的定义,加深对作者代码简化的理解,先上代码:
struct ev_loop
{
ev_tstamp ev_rt_now;
#define ev_rt_now ((loop)->ev_rt_now)
#define VAR(name,decl) decl;
#include "ev_vars.h"
#undef VAR
};
ev_loop是表示libev事件循环的结构体,我们看前两行就极其费解,首先定义了变量ev_tstamp ev_rt_now;其中,ev_tstamp为float的转义,这句没什么问题,即定义了一个float型变量ev_rt_now。然而作者紧接着就给来了一个相同的宏定义#define ev_rt_now ((loop)->ev_rt_now),what a fuck!初读感觉写这代码的人真的脑抽了,定义的宏和上一行定义的变量名一模一样!这不会有问题?然而代码跑起来依然是好好的。那么这么定义会带来什么样的结果呢?作者又为什么要这么玩?首先,我们要理解一下宏定义的作用域,先看一个非常简单的例子:
#include
using namespace std;
int main()
{
int x=11;
cout<
这是一个非常简单的例子,两个输出结果分别是11和13,现在就比较容易理解了,C语言标准中宏定义的作用域是,从定义位置开始,到其当前所在作用域结束,也就是说在宏定义#define x 13之前我们定义了变量x,并初始化为11,在第一次cout的时候宏定义未出现,所以预编译阶段x并不会被替换成13,而仍然是变量x,随后由于加入宏定义#define x 13,后面所有的x都会被替换为常量13。理解了这些,那么就比较容易理解了ev_loop的结构了,ev_loop的定义在ev.c文件中,首先定义了float成员变量ev_rt_now,由于此时宏定义#define ev_rt_now ((loop)->ev_rt_now)在其后面,故预编译并不会替换变量ev_rt_now,也就是对于结构体定义本身来说其和代码
struct ev_loop
{
ev_tstamp ev_rt_now;
#define VAR(name,decl) decl;
#include "ev_vars.h"
#undef VAR
};
的效果是一样的,宏定义并不会成为结构体成员,也不会替换其前面的结构体变量ev_rt_now。而在此之后,ev_rt_now都会被替换为((loop)->ev_rt_now),那作者为什么要做这种替换呢,我们沿着ev.c的代码往下找,3097行可以找到如下代码:
ev_loop_new (unsigned int flags) EV_THROW
{
EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop));
memset (EV_A, 0, sizeof (struct ev_loop));
loop_init (EV_A_ flags);
if (ev_backend (EV_A))
return EV_A;
ev_free (EV_A);
return 0;
}
可以找到EV_P这个宏定义实际为 struct ev_loop *loop,而loop_init定义也在ev.c,其中部分代码如下:
loop_init (EV_P_ unsigned int flags) EV_THROW
{
if (!backend)
{
origflags = flags;
#if EV_USE_REALTIME
if (!have_realtime)
{
struct timespec ts;
if (!clock_gettime (CLOCK_REALTIME, &ts))
have_realtime = 1;
}
#endif
#if EV_USE_MONOTONIC
if (!have_monotonic)
{
struct timespec ts;
if (!clock_gettime (CLOCK_MONOTONIC, &ts))
have_monotonic = 1;
}
#endif
/* pid check not overridable via env */
#ifndef _WIN32
if (flags & EVFLAG_FORKCHECK)
curpid = getpid ();
#endif
if (!(flags & EVFLAG_NOENV)
&& !enable_secure ()
&& getenv ("LIBEV_FLAGS"))
flags = atoi (getenv ("LIBEV_FLAGS"));
ev_rt_now = ev_time ();
mn_now = get_clock ();
now_floor = mn_now;
rtmn_diff = ev_rt_now - mn_now;
其中倒数第四行可以看到代码ev_rt_now = ev_time (),看到这里,差不多明白了。也就是对于新建一个事务结构体struct ev_loop的实例(ev_loop_new函数来实现),需要分配内存、初始化其成员变量并返回指向该内存的指针,代码中这个指针变量名为loop( struct ev_loop *loop),先分配内存(EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop));),后续初始化其成员变量的话需要通过指针调用的方式来进行,若不加此宏定义,那么ev_rt_now = ev_time ()必须改为loop->ev_rt_now=ev_time (),显然就不如之前的代码看起来简洁(不过我还是要说,简洁是简洁了,读起来是真累啊,%>_<%)。ev_loop结构体其他变量的调用也是这么实现的,变量定义在#ev_vars.h中,#include "ev_vars.h"在结构体中,故这里定义了结构体的其他成员变量,定义完ev_loop结构体后,紧跟着的一行代码是
#include "ev_wrap.h"
er_wrap.h的内容如下:
#ifndef EV_WRAP_H
#define EV_WRAP_H
#define acquire_cb ((loop)->acquire_cb)
#define activecnt ((loop)->activecnt)
#define anfdmax ((loop)->anfdmax)
#define anfds ((loop)->anfds)
#define async_pending ((loop)->async_pending)
#define asynccnt ((loop)->asynccnt)
#define asyncmax ((loop)->asyncmax)
#define asyncs ((loop)->asyncs)
#define backend ((loop)->backend)
#define backend_fd ((loop)->backend_fd)
#define backend_mintime ((loop)->backend_mintime)
#define backend_modify ((loop)->backend_modify)
#define backend_poll ((loop)->backend_poll)
#define checkcnt ((loop)->checkcnt)
#define checkmax ((loop)->checkmax)
#define checks ((loop)->checks)
#define cleanupcnt ((loop)->cleanupcnt)
#define cleanupmax ((loop)->cleanupmax)
#define cleanups ((loop)->cleanups)
#define curpid ((loop)->curpid)
#define epoll_epermcnt ((loop)->epoll_epermcnt)
#define epoll_epermmax ((loop)->epoll_epermmax)
#define epoll_eperms ((loop)->epoll_eperms)
#define epoll_eventmax ((loop)->epoll_eventmax)
#define epoll_events ((loop)->epoll_events)
#define evpipe ((loop)->evpipe)
#define fdchangecnt ((loop)->fdchangecnt)
#define fdchangemax ((loop)->fdchangemax)
#define fdchanges ((loop)->fdchanges)
#define forkcnt ((loop)->forkcnt)
#define forkmax ((loop)->forkmax)
#define forks ((loop)->forks)
#define fs_2625 ((loop)->fs_2625)
#define fs_fd ((loop)->fs_fd)
#define fs_hash ((loop)->fs_hash)
#define fs_w ((loop)->fs_w)
#define idleall ((loop)->idleall)
#define idlecnt ((loop)->idlecnt)
#define idlemax ((loop)->idlemax)
#define idles ((loop)->idles)
#define invoke_cb ((loop)->invoke_cb)
#define io_blocktime ((loop)->io_blocktime)
#define iocp ((loop)->iocp)
#define kqueue_changecnt ((loop)->kqueue_changecnt)
#define kqueue_changemax ((loop)->kqueue_changemax)
#define kqueue_changes ((loop)->kqueue_changes)
#define kqueue_eventmax ((loop)->kqueue_eventmax)
#define kqueue_events ((loop)->kqueue_events)
#define kqueue_fd_pid ((loop)->kqueue_fd_pid)
#define loop_count ((loop)->loop_count)
#define loop_depth ((loop)->loop_depth)
#define loop_done ((loop)->loop_done)
#define mn_now ((loop)->mn_now)
#define now_floor ((loop)->now_floor)
#define origflags ((loop)->origflags)
#define pending_w ((loop)->pending_w)
#define pendingcnt ((loop)->pendingcnt)
#define pendingmax ((loop)->pendingmax)
#define pendingpri ((loop)->pendingpri)
#define pendings ((loop)->pendings)
#define periodiccnt ((loop)->periodiccnt)
#define periodicmax ((loop)->periodicmax)
#define periodics ((loop)->periodics)
#define pipe_w ((loop)->pipe_w)
#define pipe_write_skipped ((loop)->pipe_write_skipped)
#define pipe_write_wanted ((loop)->pipe_write_wanted)
#define pollcnt ((loop)->pollcnt)
#define pollidxmax ((loop)->pollidxmax)
#define pollidxs ((loop)->pollidxs)
#define pollmax ((loop)->pollmax)
#define polls ((loop)->polls)
#define port_eventmax ((loop)->port_eventmax)
#define port_events ((loop)->port_events)
#define postfork ((loop)->postfork)
#define preparecnt ((loop)->preparecnt)
#define preparemax ((loop)->preparemax)
#define prepares ((loop)->prepares)
#define release_cb ((loop)->release_cb)
#define rfeedcnt ((loop)->rfeedcnt)
#define rfeedmax ((loop)->rfeedmax)
#define rfeeds ((loop)->rfeeds)
#define rtmn_diff ((loop)->rtmn_diff)
#define sig_pending ((loop)->sig_pending)
#define sigfd ((loop)->sigfd)
#define sigfd_set ((loop)->sigfd_set)
#define sigfd_w ((loop)->sigfd_w)
#define timeout_blocktime ((loop)->timeout_blocktime)
#define timercnt ((loop)->timercnt)
#define timermax ((loop)->timermax)
#define timers ((loop)->timers)
#define userdata ((loop)->userdata)
#define vec_eo ((loop)->vec_eo)
#define vec_max ((loop)->vec_max)
#define vec_ri ((loop)->vec_ri)
#define vec_ro ((loop)->vec_ro)
#define vec_wi ((loop)->vec_wi)
#define vec_wo ((loop)->vec_wo)
#else
#undef EV_WRAP_H
#undef acquire_cb
#undef activecnt
#undef anfdmax
#undef anfds
#undef async_pending
#undef asynccnt
#undef asyncmax
#undef asyncs
#undef backend
#undef backend_fd
#undef backend_mintime
#undef backend_modify
#undef backend_poll
#undef checkcnt
#undef checkmax
#undef checks
#undef cleanupcnt
#undef cleanupmax
#undef cleanups
#undef curpid
#undef epoll_epermcnt
#undef epoll_epermmax
#undef epoll_eperms
#undef epoll_eventmax
#undef epoll_events
#undef evpipe
#undef fdchangecnt
#undef fdchangemax
#undef fdchanges
#undef forkcnt
#undef forkmax
#undef forks
#undef fs_2625
#undef fs_fd
#undef fs_hash
#undef fs_w
#undef idleall
#undef idlecnt
#undef idlemax
#undef idles
#undef invoke_cb
#undef io_blocktime
#undef iocp
#undef kqueue_changecnt
#undef kqueue_changemax
#undef kqueue_changes
#undef kqueue_eventmax
#undef kqueue_events
#undef kqueue_fd_pid
#undef loop_count
#undef loop_depth
#undef loop_done
#undef mn_now
#undef now_floor
#undef origflags
#undef pending_w
#undef pendingcnt
#undef pendingmax
#undef pendingpri
#undef pendings
#undef periodiccnt
#undef periodicmax
#undef periodics
#undef pipe_w
#undef pipe_write_skipped
#undef pipe_write_wanted
#undef pollcnt
#undef pollidxmax
#undef pollidxs
#undef pollmax
#undef polls
#undef port_eventmax
#undef port_events
#undef postfork
#undef preparecnt
#undef preparemax
#undef prepares
#undef release_cb
#undef rfeedcnt
#undef rfeedmax
#undef rfeeds
#undef rtmn_diff
#undef sig_pending
#undef sigfd
#undef sigfd_set
#undef sigfd_w
#undef timeout_blocktime
#undef timercnt
#undef timermax
#undef timers
#undef userdata
#undef vec_eo
#undef vec_max
#undef vec_ri
#undef vec_ro
#undef vec_wi
#undef vec_wo
#endif
显然套路都是一样的,先定义结构体中的变量,保证结构体内的变量不会被宏定义替换,后加宏定义保证后面代码的简洁性。
好啦,至此我们明白了整个ev_loop的结构,瞻仰下大神的精妙设计!但还是想奉劝一句,平时写代码最好不要这么玩,很容易出错的!!!很容易挨揍!!!
,