C語言 宏陷阱與缺陷

1. 不能忽視宏定義中的空格

#define f (x) ((x)-1)

上面的宏定義中展開后變成

(x) ((x)-1)

而不是

((x)-1)

因為在f和后面的(x)之間多了一個空格赂毯!所以如果希望定義f(x)((x)-1)焰盗,必須要這樣寫:

#define f(x) ((x)-1)

但調(diào)用宏的時候卻可以有空格可很,即在上面完成宏定義后钠署,f(3)f (3)求值后都等于2.

2. 宏并不是函數(shù)

#define MAX(a,b) ((a)>(b)?(a):(b))

int max(int a, int b)
{
    return (a>b?a:b);
}

在宏定義中允青,當一個操作數(shù)被兩處用到時萌衬,就會被求值2次姜盈,但是函數(shù)不會径缅!

int MAX_Val = 0,max_Val = 0;
int a=3,b=2;

MAX_Val = MAX(++a,b);
max_Val = max(++a,b);

運行結(jié)果MAX_Valmax_Val是不相等的中符,原因是因為宏展開時變成:

((++a)>(b)?(++a):(b))

在這里++a運算了兩次姜胖!

以前經(jīng)常聽到別人說用宏定義代替函數(shù)是“用空間換時間”,原因是在C語言中調(diào)用函數(shù)時造成的系統(tǒng)開銷要大大多于函數(shù)體內(nèi)的實際計算操作淀散,所以用宏定義免去了調(diào)用函數(shù)的開銷右莱,自然時間就省了出來。但是宏展開可能產(chǎn)生非常龐大的表達式档插,占用的空間遠遠超過了編程者所期望的空間慢蜓。例如:

#define max((a)>(b)?(a):(b))

假如用上面定義的宏max,來找到a,b,c,d四個數(shù)的最大者郭膛,首先想到的寫法是:

max(a,max(b,max(c,d)))

展開后就是:

((a)>(((b)>(((c)>(d)?(c):(d)))?(b):(((c)>(d)?(c):(d)))))?(a):(((b)>(((c)>(d)?(c):(d)))?(b):(((c)>(d)?(c):(d))))))

這個式子太長了晨抡!如果調(diào)整下,寫成:

max(max(a,b),max(a,b))

展開后

((((a)>(b)?(a):(b)))>(((c)>(d)?(c):(d)))?(((a)>(b)?(a):(b))):(((c)>(d)?(c):(d))))

還是比較長则剃。

如果換成函數(shù)耘柱,更容易些!

int max(int a,int b,int c,int d)
{
    int biggest = a;
    if(biggest < b) biggest = b;
    if(biggest < c) biggest = c;
    if(biggest < d) biggest = d;
    return biggest;
}

3. 宏并不是語句

#define assert(e) if(!(e)) assert_error(__FILE__,__LINE__)

assert的這個定義棍现,即使用在一個再明白直接不過的情形中调煎,也會有一些難以察覺的錯誤。

if(x>0 && y>0)
    assert(x>y);
else
    assert(y>x);

展開后并做縮排處理:

if(x>0 && y>0)
    if(!(x>y))
        assert_error(__FILE__,__LINE__);
    else
        if(!(y>x))
            assert_error(__FILE__,__LINE__);

這與我們所期望的流程結(jié)構(gòu)不一樣己肮!

如果在宏assert的定義中用大括號把宏體整個給“括”起來士袄,那就沒有這樣的流程結(jié)構(gòu)錯誤。但是依然有問題產(chǎn)生:

#define assert(e) \
    {if(!(e)) assert_error(__FILE__,__LINE__);}

繼續(xù)拿上面的例子谎僻,展開后變成

if(x>0 && y>0)
    {if(!(x>y)) assert_error(__FILE__,__LINE__);};
else
    {if(!(y>x)) assert_error(__FILE__,__LINE__);};

上面展開后在else之前的分號是一個語法錯誤窖剑。要解決這個問題,一個辦法是對assert的調(diào)用后面都不要再跟一個分號戈稿,另外一個辦法是:

#define assert(e) \
    ((void)((e)||assert_error(__FILE__,__LINE__)))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末西土,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鞍盗,更是在濱河造成了極大的恐慌需了,老刑警劉巖跳昼,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肋乍,居然都是意外死亡鹅颊,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門墓造,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堪伍,“玉大人,你說我怎么就攤上這事觅闽〉酃停” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵蛉拙,是天一觀的道長尸闸。 經(jīng)常有香客問我,道長孕锄,這世上最難降的妖魔是什么吮廉? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮畸肆,結(jié)果婚禮上宦芦,老公的妹妹穿的比我還像新娘。我一直安慰自己轴脐,他們只是感情好踪旷,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著豁辉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舀患。 梳的紋絲不亂的頭發(fā)上徽级,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機與錄音聊浅,去河邊找鬼餐抢。 笑死,一個胖子當著我的面吹牛低匙,可吹牛的內(nèi)容都是我干的旷痕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼顽冶,長吁一口氣:“原來是場噩夢啊……” “哼欺抗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起强重,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤绞呈,失蹤者是張志新(化名)和其女友劉穎贸人,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佃声,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡艺智,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了圾亏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片十拣。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖志鹃,靈堂內(nèi)的尸體忽然破棺而出夭问,到底是詐尸還是另有隱情,我是刑警寧澤弄跌,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布甲喝,位于F島的核電站,受9級特大地震影響铛只,放射性物質(zhì)發(fā)生泄漏埠胖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一淳玩、第九天 我趴在偏房一處隱蔽的房頂上張望直撤。 院中可真熱鬧,春花似錦蜕着、人聲如沸谋竖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蓖乘。三九已至,卻和暖如春韧骗,著一層夾襖步出監(jiān)牢的瞬間嘉抒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工袍暴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留些侍,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓政模,卻偏偏與公主長得像岗宣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子淋样,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

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