libev中ev_loop結構體中巨集定義的理解
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_tstamp。然而作者緊接著就給來了一個相同的巨集定義#define ev_rt_now ((loop)->ev_rt_now),what a fuck!初讀感覺寫這程式碼的人真的腦抽了,定義的巨集和上一行定義的變數名一模一樣!這不會有問題?然而程式碼跑起來依然是好好的。那麼這麼定義會帶來什麼樣的結果呢?作者又為什麼要這麼玩?首先,我們要理解一下巨集定義的作用域,先看一個非常簡單的例子:
#include<iostream>
using namespace std;
int main()
{
int x=11;
cout<<x<<endl;
#define x 13
cout<<x<<endl;
return 0;
}
//輸出結果:
//11
//13
這是一個非常簡單的例子,兩個輸出結果分別是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的結構,瞻仰下大神的精妙設計!但還是想奉勸一句,平時寫程式碼最好不要這麼玩,很容易出錯的!!!很容易捱揍!!!
,
相關文章
- C++中巨集定義#define的用法C++
- C語言巨集定義中#define中的井號#的使用C語言
- 巨集定義
- C語言中的標頭檔案中的巨集定義C語言
- 從 CPU 角度理解 Go 中的結構體記憶體對齊Go結構體記憶體
- go中map的資料結構理解Go資料結構
- 關於malloc原始碼中的bin_at巨集定義的個人見解原始碼
- 記憶體對齊巨集定義的簡明解釋記憶體
- Runtime中的 isa 結構體結構體
- 定時中斷基本結構
- sqlite中存放自定義表結構的位置SQLite
- java中serverlet的體系結構JavaServer
- C語言-->(十四)結構體、巨集、編譯C語言結構體編譯
- 分享一個無需定義結構體解析json的包結構體JSON
- c 語言中巨集定義和定義全域性變數的區別變數
- HTML中Progress標籤的定義及用法總結!HTML
- 巨集定義跟多個引數
- 如何定義一個自帶資料區的結構體:三種資料結構體的比較結構體資料結構
- C 結構體中的位域概念結構體
- 理解TON合約中的訊息傳送結構
- 【SqlServer】 理解資料庫中的資料頁結構SQLServer資料庫
- 從一份定義檔案詳解ELK中Logstash外掛結構
- 0x03. 使用巨集定義事件事件
- iOS-日常開發常用巨集定義iOS
- Salt Highstate資料結構定義資料結構
- JS中EventLoop、巨集任務與微任務的個人理解JSOOP
- Unity中的自動更新目錄結構設定Unity
- gcc編譯階段列印巨集定義的內容GC編譯
- 認真一點學 Go:12. 自定義型別和結構體 - 定義Go型別結構體
- 【C進階】21、巨集定義與使用分析
- google guava中定義的String操作GoGuava
- 物聯網學習教程—定義結構體型別變數的方法結構體型別變數
- 探索 DTD 在 XML 中的作用及解析:深入理解文件型別定義XML型別
- InfluxDB中的inmem記憶體索引結構解析UX記憶體索引
- C# 中的只讀結構體(readonly struct)C#結構體Struct
- 理解JVM(一):記憶體結構JVM記憶體
- C# 中 System.Range 結構體C#結構體
- JavaScript中的程式結構和分支結構JavaScript