重載宏函數(shù)

bhook里有一段重載宏函數(shù)的實現(xiàn):

#define BYTESIG_TRY(...)                                                                                   \
  do {                                                                                                     \
    pid_t _bytesig_tid_ = gettid();                                                                        \
    if (0 == _bytesig_tid_) _bytesig_tid_ = (pid_t)syscall(SYS_gettid);                                    \
    sigjmp_buf _bytesig_jbuf_;                                                                             \
    int _bytesig_sigs_[] = {__VA_ARGS__};                                                                  \
    bytesig_protect(_bytesig_tid_, &_bytesig_jbuf_, _bytesig_sigs_, sizeof(_bytesig_sigs_) / sizeof(int)); \
    int _bytesig_protected_ = 1;                                                                           \
    int _bytesig_ex_ = sigsetjmp(_bytesig_jbuf_, 1);                                                       \
    if (0 == _bytesig_ex_) {
#define BYTESIG_CATCH_2(signum_, code_)                                                     \
  }                                                                                         \
  else {                                                                                    \
    bytesig_unprotect(_bytesig_tid_, _bytesig_sigs_, sizeof(_bytesig_sigs_) / sizeof(int)); \
    _bytesig_protected_ = 0;                                                                \
    int signum_ = (int)(((unsigned int)_bytesig_ex_ & 0xFF0000U) >> 16U);                   \
    int code_ = 0;                                                                          \
    if (((unsigned int)_bytesig_ex_ & 0xFF00U) > 0)                                         \
      code_ = (int)(((unsigned int)_bytesig_ex_ & 0xFF00U) >> 8U);                          \
    else if (((unsigned int)_bytesig_ex_ & 0xFFU) > 0)                                      \
      code_ = -((int)((unsigned int)_bytesig_ex_ & 0xFFU));                                 \
    (void)signum_;                                                                          \
    (void)code_;

#define BYTESIG_CATCH_1(signum_) BYTESIG_CATCH_2(signum_, _bytesig_code_)
#define BYTESIG_CATCH_0()        BYTESIG_CATCH_1(_bytesig_signum_)

#define FUNC_CHOOSER(_f1, _f2, _f3, ...)     _f3
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(...)           FUNC_RECOMPOSER((__VA_ARGS__, BYTESIG_CATCH_2, BYTESIG_CATCH_1, ))
#define NO_ARG_EXPANDER()                    , , BYTESIG_CATCH_0
#define MACRO_CHOOSER(...)                   CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__())

#define BYTESIG_CATCH(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)

#define BYTESIG_EXIT                                                                        \
  }                                                                                         \
  if (1 == _bytesig_protected_)                                                             \
    bytesig_unprotect(_bytesig_tid_, _bytesig_sigs_, sizeof(_bytesig_sigs_) / sizeof(int)); \
  }                                                                                         \
  while (0);

/*
    int *p = NULL;

     //
     // usage 1
     //
     BYTESIG_TRY(SIGSEGV, SIGBUS)
     {
         *p = 1;
     }
     BYTESIG_CATCH(signum, code)
     {
         LOG("signum %d (code %d)", signum, code);
     }
     BYTESIG_EXIT

     //
     // usage 2
     //
     BYTESIG_TRY(SIGSEGV, SIGBUS)
     {
         *p = 2;
     }
     BYTESIG_CATCH(signum)
     {
         LOG("signum %d", signum);
     }
     BYTESIG_EXIT

     //
     // usage 3
     //
     BYTESIG_TRY(SIGILL)
     {
         func_maybe_illed();
     }
     BYTESIG_CATCH()
     {
         do_something();
     }
     BYTESIG_EXIT

     //
     // usage 4
     //
     BYTESIG_TRY(SIGABRT)
     {
         func_maybe_aborted();
     }
     BYTESIG_EXIT
*/

BYTESIG_CATCH推導(dǎo)過程

BYTESIG_TRY宏和BYTESIG_EXIT宏都很容易理解,但是BYTESIG_CATCH宏卻存在三種用法BYTESIG_CATCH()\BYTESIG_CATCH(signum)\BYTESIG_CATCH(signum, code)。那我們一起看下BYTESIG_CATCH的實現(xiàn)。
BYTESIG_CATCH_2宏是BYTESIG_CATCH的最終實現(xiàn),為兩個參數(shù)版本,BYTESIG_CATCH_1為單個參數(shù)版本,BYTESIG_CATCH_0為無參數(shù)版本。我們大膽的猜測,

BYTESIG_CATCH(signum, code)
BYTESIG_CATCH(signum)
BYTESIG_CATCH()

最終會被推導(dǎo)成

BYTESIG_CATCH_2(signum, code)
BYTESIG_CATCH_1(signum)
BYTESIG_CATCH_0()

根據(jù)上述猜想,我們推斷MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)會被拆解兩部分,第一部分MACRO_CHOOSER(__VA_ARGS__)被推導(dǎo)成宏定義的名稱,第二部分(__VA_ARGS__)會被推導(dǎo)成參數(shù)列表,拿BYTESIG_CATCH(signum, code)舉例,MACRO_CHOOSER(__VA_ARGS__)被解釋成BYTESIG_CATCH_2,(signum, code)被解釋成(signum, code)

那開始我們的推導(dǎo)步驟:

BYTESIG_CATCH(signum, code)
BYTESIG_CATCH(signum)
BYTESIG_CATCH()

先被推導(dǎo)成

CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER signum, code())(signum, code)
CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER signum())(signum)
CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER ())()

下一步被推導(dǎo)成

FUNC_RECOMPOSER((NO_ARG_EXPANDER signum, code(), BYTESIG_CATCH_2, BYTESIG_CATCH_1, ))(signum, code)
FUNC_RECOMPOSER((NO_ARG_EXPANDER signum(), BYTESIG_CATCH_2, BYTESIG_CATCH_1, ))(signum)
FUNC_RECOMPOSER((NO_ARG_EXPANDER (), BYTESIG_CATCH_2, BYTESIG_CATCH_1, ))()

下一步被推導(dǎo)成

FUNC_CHOOSER (NO_ARG_EXPANDER signum, code(), BYTESIG_CATCH_2, BYTESIG_CATCH_1, )(signum, code)
FUNC_CHOOSER (NO_ARG_EXPANDER signum(), BYTESIG_CATCH_2, BYTESIG_CATCH_1, )(signum)
FUNC_CHOOSER (NO_ARG_EXPANDER (), BYTESIG_CATCH_2, BYTESIG_CATCH_1, )()

這里需要特別注意,預(yù)處理器僅執(zhí)行簡單的文本替換。它僅從在括號內(nèi)看到的逗號數(shù)推斷出宏函數(shù)的參數(shù)個數(shù),用逗號分隔的“參數(shù)”不必具有有效的語法,這些參數(shù)可以是任何文本,也就是說在上面的示例中,NO_ARG_EXPANDER signum, code(), BYTESIG_CATCH_2, BYTESIG_CATCH_1,總共四個逗號,被視為四個參數(shù),第一個參數(shù)是NO_ARG_EXPANDER signum,第二個參數(shù)是code(),第三個參數(shù)是BYTESIG_CATCH_2,第四個參數(shù)是BYTESIG_CATCH_1。
下一步被推導(dǎo)成

BYTESIG_CATCH_2(signum, code)
BYTESIG_CATCH_1(signum)
FUNC_CHOOSER (, , BYTESIG_CATCH_0, BYTESIG_CATCH_2, BYTESIG_CATCH_1, )()

下一步被推導(dǎo)成

BYTESIG_CATCH_2(signum, code)
BYTESIG_CATCH_1(signum)
BYTESIG_CATCH_0()

BYTESIG_TRY Vs. BYTESIG_CATCH

從示例中我們可以看出BYTESIG_TRY也存在多種用法BYTESIG_TRY(SIGSEGV, SIGBUS)/BYTESIG_TRY(SIGILL)/BYTESIG_TRY(SIGABRT),而BYTESIG_TRY的實現(xiàn)卻比BYTESIG_CATCH簡單的多,這兩種到底有什么區(qū)別呢?

BYTESIG_TRY(SIGSEGV, SIGBUS)
{
    *p = 1;
}
BYTESIG_CATCH(signum, code)
{
    LOG("signum %d (code %d)", signum, code);
}
BYTESIG_EXIT

仔細(xì)觀看會發(fā)現(xiàn),BYTESIG_CATCH塊內(nèi)使用了BYTESIG_CATCH的參數(shù)signumcode,而BYTESIG_TRY并沒有,即BYTESIG_CATCH是指定了BYTESIG_CATCH塊內(nèi)局部變量的名稱。如果宏塊內(nèi)不需要指定的參數(shù)即塊內(nèi)局部變量,可直接使用BYTESIG_TRY的實現(xiàn)方式#define BYTESIG_TRY(...)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 在ReactiveCocoa 中,開源庫作者為我們提供了很多種魔法,“黑”魔法,“紅”魔法……今天就讓先來看...
    一縷殤流化隱半邊冰霜閱讀 9,407評論 20 97
  • 在RAC里面遇到了大量的宏定義謹(jǐn)以此篇文章記錄一下理解這些宏定義的過程 名詞解釋 變量名: 類似于 NSStri...
    傳說中的汽水槍閱讀 400評論 0 2
  • 最常見的就是 #indef __cplusplus 這表示支持C++語法 再如可以定義常量 #define MAX...
    貝克街的貓大哥呀閱讀 4,317評論 0 0
  • 宏定義在C系開發(fā)中可以說占有舉足輕重的作用。底層框架自不必說,為了編譯優(yōu)化和方便,以及跨平臺能力,宏被大量使用,可...
    你好自己閱讀 1,125評論 0 5
  • 喜歡讀一些開源項目源碼的人,總是會發(fā)現(xiàn),大神的代碼中總是有那么一些簡短而高效的宏定義,點擊進(jìn)去一看,發(fā)現(xiàn)晦澀難懂,...
    我是強強閱讀 337評論 0 0

友情鏈接更多精彩內(nèi)容