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