函式巨集,即包含多條語句的巨集定義,其通常為某一被頻繁呼叫的功能的語句封裝,且不想通過函式方式封裝來降低額外的彈棧壓棧開銷。
函式巨集本質上為巨集,可以直接進行定義,例如:
#define int_swap(a,b) \
int tmp = a; \
a = b; \
b = tmp
但上述的巨集具有乙個明顯的缺點:當遇到if
、while
等語句且不使用花括號僅呼叫巨集時,實際作用範圍在巨集的第乙個分號後便結束。即a = b
和b = tmp
均不受控制語句所作用。
因此,在工程中,一般使用三種方式來對函式巨集進行封裝,分別為{}
、dowhile(0)
和({})
。下文將一一對三種方式進行分析,比較各自的優劣點。
int_swap
巨集使用{}
封裝後形態如下:
#define int_swap(a,b)\
此時,直接呼叫與在無花括號的控制語句(如if
、while
)中呼叫均能正常執行,例如:
#define int_swap(a,b) \
int main()
但當無花括號的if
語句存在其他分支(else if
、else
等)如:
if (1)
int_swap(var_a, var_b);
else
printf("hello world!\n");
會發現編譯出錯:
...
/mnt/hgfs/share/pr_c/src/main.c: in function 『main』:
/mnt/hgfs/share/pr_c/src/main.c:18:2: error: 『else』 without a previous 『if』
else
這是因為int_swap(var_a, var_b);
最後的;
已經把if
的作用域終結了,後續的else
當然沒有找到與之匹配的if
了。
因此,解決方法有兩種,分別為不使用;
(port.1)或規定必須使用帶花括號的if
(port.2),例如:
/* port.1 */
if (1)
int_swap(var_a, var_b)
else
/* port.2 */
if (1)
else
可見,不使用;
的呼叫方式無論從程式閱讀還是使用方法方面都是十分彆扭的;而規定必須使用帶花括號的if
的呼叫方式有違常理的,因為巨集函式應該適用於任何語法。
優缺點總結:
int_swap
巨集使用dowhile(0)
封裝後形態如下:
#define int_swap(a,b) \
dowhile(0)
dowhile(0)
表示只執行一遍{}
內的語句,表象來說與{}
的功能是一致的。不同的是,dowhile(0)
可以提前退出函式巨集、集成為一條語句與強制呼叫時必須使用;
。
由於dowhile(0)
實際為 while 迴圈,因此可以使用關鍵字break
提前結束迴圈。利用該特性,可以為函式巨集新增引數檢測。例如:
#define int_swap(a,b) \
dowhile(0)
由於dowhile(0);
實際為一種語法,編譯器會把dowhile(0);
認為為一條語句。
因此,dowhile(0)
方式的函式巨集可以在無花括號且有分支的if
語句中直接呼叫。例如:
#define int_swap(a,b) \
dowhile(0)
int main()
c 語言規定,dowhile(0)
語法必須使用;
作為語句結尾。因此不可能存在以下語句的程式出現:
if (1)
int_swap(var_a, var_b)
else
優缺點總結:
({})
為 gnu c 擴充套件的語法,非 c 語言的原生語法。
int_swap
巨集使用({})
封裝後形態如下:
#define int_swap(a,b) \
()
與dowhile(0)
相同,({})
支援在無花括號且有分支的if
語句中直接呼叫。例如:
#define int_swap(a,b) \
()int main()
與dowhile(0)
不同的是,({})
不能提前退出函式巨集與支援返回值。({})
畢竟不是 while 迴圈,不能直接使用break
退出函式巨集是比較容易理解。那支援返回值是什麼意思呢?
答案是 c 語言規定({})
中的最後一條語句的結果為該雙括號體的返回值。例如:
int main());
printf("a = %d\n", a); // a = 1000
}
因此,({})
可以為函式巨集提供返回值。例如:
#define int_swap(a,b) \
( \else \
\ret; \
})int main()
可見,此時的int_swap
巨集已與函式十分接近。
優缺點總結:
綜上,在{}
、dowhile(0)
和({})
這三種函式巨集的封裝方式之中,應盡可能不使用{}
,考慮相容性一般選擇使用dowhile(0)
,當需要函式巨集返回時可以考慮使用({})
或直接定義函式。
c語言、嵌入式中幾個非常實用的巨集技巧
c語言高效程式設計與**優化
函式的寫法 C 建構函式的三種寫法
c 的建構函式的作用 初始化類物件的資料成員。即類的物件被建立的時候,編譯系統對該物件分配記憶體空間,並自動呼叫建構函式,完成類成員的初始化。建構函式的特點 以類名作為函式名,無返回型別。常見的建構函式有三種寫法 c 的建構函式可以有多個,建立物件時編譯器會根據傳入的引數不同呼叫不同的建構函式。如果...
C 函式引數傳遞的三種方式
1.值傳遞 void myswap01 int a,int b 2.位址傳遞 void myswap02 int a,int b 3.引用傳遞 void myswap03 int a,int b int main 結果 值傳遞並不改變實參的大小,位址傳遞和引用傳遞均改變位址大小。原因是什麼?是因為考...
javascript三種函式形式
1.普通函式 function show message show test 定義 同python中函式定義方法一致,關鍵字替換為function 執行 呼叫方法和一般語言中呼叫方法一致,可有返回值 2.匿名函式 setinterval function 1000 a function messag...