語(yǔ)法錯(cuò)誤
當(dāng)使用參數(shù)調(diào)用宏時(shí),會(huì)將參數(shù)替換為宏主體,并與其他輸入文件一起檢查結(jié)果,以進(jìn)行更多的宏調(diào)用,可以將部分來(lái)自宏主體和部分自變量的宏調(diào)用組合在一起。例如,
#define twice(x) (2*(x))
#define call_with_1(x) x(1)
call_with_1 (twice)
//x=1
→ twice(1)
→ (2*(1))
宏定義不必帶有括號(hào),通過(guò)在宏主體中編寫(xiě)不平衡的開(kāi)放括號(hào),可以創(chuàng)建一個(gè)從宏主體內(nèi)部開(kāi)始但在宏主體外部結(jié)束的宏調(diào)用。例如,
#define strange(file) fprintf (file, "%s %d",
…
strange(stderr) p, 35)
→ fprintf (stderr, "%s %d", p, 35)
組合宏調(diào)用的功能可能會(huì)很有用,但是在宏主體中使用不平衡的開(kāi)放括號(hào)只會(huì)造成混淆,應(yīng)該避免。
運(yùn)算符優(yōu)先級(jí)問(wèn)題
在大多數(shù)宏定義示例中,每次出現(xiàn)的宏參數(shù)名稱都帶有括號(hào),并且另一對(duì)括號(hào)通常會(huì)包圍整個(gè)宏定義,這是編寫(xiě)宏最好的方式。舉個(gè)例子
#define ceil_div(x, y) (x + y - 1) / y
假定其用法如下:
a = ceil_div(b&c,sizeof(int));
拓展開(kāi)是
a =(b&c + sizeof(int)-1)/ sizeof(int);
這沒(méi)有達(dá)到我們的預(yù)期,C的運(yùn)算符優(yōu)先級(jí)規(guī)則使其等效于此,而我們想要的是:
a =(((b&c)+ sizeof(int)-1))/ sizeof(int);
如果我們將宏定義為
#define ceil_div(x,y)((x)+(y)-1)/(y)
可能導(dǎo)致另一種情況,sizeof ceil_div(1,2)是一個(gè)C表達(dá)式,可以計(jì)算ceil_div(1,2)類型的大小,它擴(kuò)展為:
sizeof((1)+(2)-1)/(2)
這將采用整數(shù)的大小并將其除以2,而除法包含在內(nèi)部的sizeof之外。所以整個(gè)宏定義的括號(hào)可防止此類問(wèn)題。那么,下面是定義ceil_div的正確方法如下
#define ceil_div(x,y)((((x)+(y)-1)/(y))
吞噬分號(hào)
通常需要定義一個(gè)擴(kuò)展為復(fù)合語(yǔ)句的宏。例如,考慮以下宏,該宏跨空格字符前進(jìn)一個(gè)指針(參數(shù)p表示在何處查找):
#define SKIP_SPACES(p, limit)
{ char *lim = (limit);
while (p < lim) {
if (*p++ != ' ') {
p--; break; }}}
該宏定義必須是單個(gè)邏輯行,嚴(yán)格來(lái)說(shuō),該調(diào)用擴(kuò)展為復(fù)合語(yǔ)句,這是一個(gè)完整的語(yǔ)句,不需要用分號(hào)結(jié)束。
但是,由于它看起來(lái)像函數(shù)調(diào)用,因此,如果可以像使用函數(shù)調(diào)用一樣使用它,則可以最大程度地減少混亂,然后再寫(xiě)一個(gè)分號(hào),就像在SKIP_SPACES(p,lim)中一樣。
這可能會(huì)在else語(yǔ)句之前出問(wèn)題,因?yàn)榉痔?hào)實(shí)際上是空語(yǔ)句。假設(shè)你寫(xiě)
if (*p != 0)
SKIP_SPACES (p, lim);
else …
在if條件和else條件之間存在兩個(gè)語(yǔ)句(復(fù)合語(yǔ)句和null語(yǔ)句)使C代碼無(wú)效。
怎么解決?我們可以使用do…while語(yǔ)句更改宏SKIP_SPACES的定義以解決此問(wèn)題。方法如下:
#define SKIP_SPACES(p, limit)
do { char *lim = (limit);
while (p < lim) {
if (*p++ != ' ') {
p--; break; }}}
while (0)
SKIP_SPACES (p, lim);擴(kuò)展為
do {…} while (0);
這是一個(gè)陳述,循環(huán)僅執(zhí)行一次,而且大多數(shù)編譯器不會(huì)為此生成任何額外的代碼。
-
函數(shù)
+關(guān)注
關(guān)注
3文章
4329瀏覽量
62576 -
代碼
+關(guān)注
關(guān)注
30文章
4780瀏覽量
68538
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論