Objective-C MAX MIN 宏定義

錯誤的 MIN MAX 宏定義

朋友面試時遇到的一個問題:

Define a standard macro MAX with 2 parameters. It returns the greater one.
(Please provide program segments)

第一反應(yīng)是這樣的:

#define MYMAX(A, B) (A < B ? B : A)

然而直覺告訴我問題肯定沒這么簡單嗡害,那么坑在哪里?答案是當(dāng)你使用 ++ 操作符的時候:

float a = 2.0f;
float b = MYMAX(a++, 1.5f);
NSLog(@"a = %f, b = %f", a, b);
// a = 4.000000, b = 3.000000

調(diào)用者的預(yù)期輸出應(yīng)該是 a = 3.000000, b = 2.000000,而之所以會變成 a = 4.000000, b = 3.000000亏娜,是因為經(jīng)過宏替換钳吟,上面的代碼相當(dāng)于:

float a = 2.0f;
float b = a++ < 1.5f ? 1.5f : a++;
NSLog(@"a = %f, b = %f", a, b);

可以看到凫碌,因為前面的條件為 NO,這里 a++ 相當(dāng)于執(zhí)行了兩遍餐弱。

正確的 MIN MAX 宏定義

我們測試一下蘋果提供的 MAX 方法:

float a = 2.0f;
float b = MAX(a++, 1.5f);
NSLog(@"a = %f, b = %f", a, b);
// a = 3.000000, b = 2.000000

并沒有剛才那個問題焕檬。

我們來看一下它是如何定義的:

#define __NSX_PASTE__(A,B) A##B

#if !defined(MIN)
    #define __NSMIN_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__a,L) : __NSX_PASTE__(__b,L); })
    #define MIN(A,B) __NSMIN_IMPL__(A,B,__COUNTER__)
#endif

#if !defined(MAX)
    #define __NSMAX_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__b,L) : __NSX_PASTE__(__a,L); })
    #define MAX(A,B) __NSMAX_IMPL__(A,B,__COUNTER__)
#endif

根據(jù)宏定義姆坚,我們來替換剛才的代碼:

float a = 2.0f;
float b = ({
    __typeof__(a++) __NSX_PASTE__(__a,__COUNTER__) = (a++);
    __typeof__(1.5f) __NSX_PASTE__(__b,__COUNTER__) = (1.5f);
    (__NSX_PASTE__(__a,__COUNTER__) < __NSX_PASTE__(__b,__COUNTER__)) ? __NSX_PASTE__(__b,__COUNTER__) : __NSX_PASTE__(__a,__COUNTER__);
});
NSLog(@"a = %f, b = %f", a, b);
// a = 3.000000, b = 2.000000

__COUNTER__ 是一個預(yù)定義宏,在編譯過程中從 0 開始計數(shù)揩页,每次被調(diào)用時加 1旷偿。因為唯一性,所以通常用于構(gòu)造獨立的變量名爆侣。(參考:GCC: Common Predefined Macros

__NSX_PASTE__ 是連接萍程,宏定義中不能直接寫 AB 來連接參數(shù),需要寫成 A##B兔仰。

假設(shè) COUNTER 的值為 0茫负,上面的代碼可以繼續(xù)被替換為:

float a = 2.0f;
float b = ({
    __typeof__(a++) __a0 = (a++);
    __typeof__(1.5f) __b0 = (1.5f);
    (__a0 < __b0) ? __b0 : __a0;
});
NSLog(@"a = %f, b = %f", a, b);
// a = 3.000000, b = 2.000000

可以看到,這里 a++ 同樣寫了兩次乎赴,但是在 __typeof__() 中的 a++ 并沒有執(zhí)行忍法。我只能說:

這是編譯器的特性

PS: 無論是條件運算符,還是 if 語句中的 a++榕吼,都會執(zhí)行:

float a = 2.0f;
float b;
if (a++ < 1.5f) {
    b = 1.5;
} else {
    b = a++;
}
NSLog(@"a = %f, b = %f", a, b);
// a = 4.000000, b = 3.000000
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饿序,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子羹蚣,更是在濱河造成了極大的恐慌原探,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顽素,死亡現(xiàn)場離奇詭異咽弦,居然都是意外死亡,警方通過查閱死者的電腦和手機胁出,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進(jìn)店門型型,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人全蝶,你說我怎么就攤上這事闹蒜∷峦鳎” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵嫂用,是天一觀的道長型凳。 經(jīng)常有香客問我丈冬,道長嘱函,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任埂蕊,我火速辦了婚禮往弓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蓄氧。我一直安慰自己函似,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布喉童。 她就那樣靜靜地躺著撇寞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪堂氯。 梳的紋絲不亂的頭發(fā)上蔑担,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天,我揣著相機與錄音咽白,去河邊找鬼啤握。 笑死,一個胖子當(dāng)著我的面吹牛晶框,可吹牛的內(nèi)容都是我干的排抬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼授段,長吁一口氣:“原來是場噩夢啊……” “哼蹲蒲!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侵贵,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤届搁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后模燥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咖祭,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年蔫骂,在試婚紗的時候發(fā)現(xiàn)自己被綠了么翰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡辽旋,死狀恐怖浩嫌,靈堂內(nèi)的尸體忽然破棺而出檐迟,到底是詐尸還是另有隱情,我是刑警寧澤码耐,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布追迟,位于F島的核電站,受9級特大地震影響骚腥,放射性物質(zhì)發(fā)生泄漏敦间。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一束铭、第九天 我趴在偏房一處隱蔽的房頂上張望廓块。 院中可真熱鬧,春花似錦契沫、人聲如沸带猴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拴清。三九已至,卻和暖如春会通,著一層夾襖步出監(jiān)牢的瞬間口予,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工渴语, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留苹威,地道東北人。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓驾凶,卻偏偏與公主長得像牙甫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子调违,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 宏定義在C系開發(fā)中可以說占有舉足輕重的作用窟哺。底層框架自不必說,為了編譯優(yōu)化和方便技肩,以及跨平臺能力且轨,宏被大量使用,可...
    你好自己閱讀 1,054評論 0 5
  • http://www.open-open.com/lib/view/open1390651437117.html ...
    Xtuphe閱讀 1,267評論 0 10
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理虚婿,服務(wù)發(fā)現(xiàn)旋奢,斷路器,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 走路的羨慕開車的然痊,也有人羨慕走路的至朗。盡管呼吸著同一片天的空氣,卻有著各種各樣的人生剧浸。滿足到不同層次的人就會有...
    研究說明書閱讀 349評論 0 0
  • 11月15日上午锹引,我們聆聽了來自河師大教育學(xué)院李玉芳老師的講座《漫談班主任領(lǐng)導(dǎo)力及提升》矗钟。本次講座,來自我們滑縣的...
    你是幸運的周杰閱讀 659評論 0 2