C/C++細(xì)數(shù)宏與函數(shù)有那些區(qū)別
一、宏和函數(shù)的對(duì)比
1.宏的優(yōu)點(diǎn)
- 宏通常被應(yīng)用于執(zhí)行簡單的運(yùn)算。
- 比如在兩個(gè)數(shù)中找出較大的一個(gè)。
#define MAX(a, b) ((a)>(b)?(a):(b))
那為什么不用函數(shù)來完成這個(gè)任務(wù)?
原因有兩點(diǎn):
用于調(diào)用函數(shù)和從函數(shù)返回的代碼可能比實(shí)際執(zhí)行這個(gè)小型計(jì)算工作所需要的時(shí)間更多。
所以宏比函數(shù)在程序的規(guī)模和速度方面更勝一籌。
舉例:
用宏實(shí)現(xiàn)兩個(gè)數(shù)中找出較大值。
#define MAX(x, y) ((x) > (y) ? (x) : (y)) int main() { int a = 10; int b = 20; int c = MAX(a, b); // 宏 return 0; }
轉(zhuǎn)到反匯編,查看匯編代碼。
int c = MAX(a, b); // 宏
00791783 mov eax,dword ptr [a]
00791786 cmp eax,dword ptr [b]
00791789 jle __$EncStackInitStart+3Ah (0791796h)
0079178B mov ecx,dword ptr [a]
0079178E mov dword ptr [ebp-0E8h],ecx
00791794 jmp __$EncStackInitStart+43h (079179Fh)
00791796 mov edx,dword ptr [b]
00791799 mov dword ptr [ebp-0E8h],edx
0079179F mov eax,dword ptr [ebp-0E8h]
007917A5 mov dword ptr [c],eax
用函數(shù)實(shí)現(xiàn)兩個(gè)數(shù)中找出較大值。
int Max(int x, int y) { return ((x) > (y) ? (x) : (y)); } int main() { int a = 10; int b = 20; int c = Max(a, b); // 函數(shù) return 0; }
調(diào)用函數(shù)的匯編代碼。
int c = Max(a, b); // 函數(shù)
002C1793 mov eax,dword ptr [b]
002C1796 push eax
002C1797 mov ecx,dword ptr [a]
002C179A push ecx
002C179B call _Max (02C139Dh) // 調(diào)用Max函數(shù)
002C17A0 add esp,8
002C17A3 mov dword ptr [c],eax
計(jì)算的匯編代碼。
int Max(int x, int y)
{
002C1DF0 push ebp
002C1DF1 mov ebp,esp
002C1DF3 sub esp,0C4h
002C1DF9 push ebx
002C1DFA push esi
002C1DFB push edi
002C1DFC lea edi,[ebp-4]
002C1DFF mov ecx,1
002C1E04 mov eax,0CCCCCCCCh
002C1E09 rep stos dword ptr es:[edi]
002C1E0B mov ecx,offset _66EADA86_詳解預(yù)處理\test@c (02CC000h)
002C1E10 call @__CheckForDebuggerJustMyCode@4 (02C1307h)
// 下面這些才是計(jì)算的代碼,上面這些代碼可以說還是在為調(diào)用函數(shù)做準(zhǔn)備
// 并且可以看出下面的匯編代碼和宏那里的匯編代碼是一樣的
return ((x) > (y) ? (x) : (y));
002C1E15 mov eax,dword ptr [x]
002C1E18 cmp eax,dword ptr [y]
002C1E1B jle __$EncStackInitStart+2Ch (02C1E28h)
002C1E1D mov ecx,dword ptr [x]
002C1E20 mov dword ptr [ebp-0C4h],ecx
002C1E26 jmp __$EncStackInitStart+35h (02C1E31h)
002C1E28 mov edx,dword ptr [y]
002C1E2B mov dword ptr [ebp-0C4h],edx
002C1E31 mov eax,dword ptr [ebp-0C4h]
}
函數(shù)返回的匯編代碼。
002C1E37 pop edi
002C1E38 pop esi
002C1E39 pop ebx
002C1E3A add esp,0C4h
002C1E40 cmp ebp,esp
002C1E42 call __RTC_CheckEsp (02C1230h)
002C1E47 mov esp,ebp
002C1E49 pop ebp
002C1E4A ret
總結(jié):
如果用函數(shù)的話,會(huì)經(jīng)過以下幾個(gè)步驟:
- 函數(shù)調(diào)用。
- 計(jì)算。
- 函數(shù)返回。
根據(jù)上面的匯編代碼可以看出,函數(shù)調(diào)用和函數(shù)返回所用的匯編指令遠(yuǎn)多于計(jì)算所用的匯編指令,這就導(dǎo)致函數(shù)調(diào)用和返回所用的時(shí)間遠(yuǎn)多于計(jì)算所用的時(shí)間。而宏本質(zhì)是替換,不用進(jìn)行函數(shù)調(diào)用和返回,所以這就是宏在實(shí)現(xiàn)小型計(jì)算工作時(shí)比函數(shù)快的原因。
- 更為重要的是函數(shù)的參數(shù)必須聲明為特定的類型。
所以函數(shù)只能在類型合適的表達(dá)式上使用。
而宏是類型無關(guān)的,宏可以適用于整形、長整型、浮點(diǎn)型等,可以用于 “>” 來比較的類型。
舉例:
下面為宏和函數(shù)實(shí)現(xiàn)的兩個(gè)數(shù)中找出較大值。
// 宏 #define MAX(x, y) ((x) > (y) ? (x) : (y)) // 函數(shù) int Max(int x, int y) { return ((x) > (y) ? (x) : (y)); }
可以看出,該函數(shù)只能對(duì)兩個(gè)int類型的數(shù)進(jìn)行比較,而宏卻可以對(duì)兩個(gè)任意類型的數(shù)進(jìn)行比較,這就使宏用起來更加的靈活。
2.宏的缺點(diǎn)
- 每次使用宏的時(shí)候,一份宏定義的代碼將插入到程序中。除非宏比較短,否則可能大幅度增加程序的長度。
- 宏是沒法調(diào)試的。
- 宏由于類型無關(guān),也就不夠嚴(yán)謹(jǐn)。
- 宏可能會(huì)帶來運(yùn)算符優(yōu)先級(jí)的問題,導(dǎo)致程容易出現(xiàn)錯(cuò)。
3.宏的獨(dú)特性
宏有時(shí)候可以做函數(shù)做不到的事情。
比如:宏的參數(shù)可以出現(xiàn)類型,但是函數(shù)做不到。
#define MALLOC(num, type) (type*)malloc(num * sizeof(type)) int main() { // 使用 int* p1 = MALLOC(10, int); // 替換后為 int* p1 = (int*)malloc(10 * sizeof(int)); char* p2 = MALLOC(5, int); // 替換后為 int* p2 = (char*)malloc(5 * sizeof(char)); return 0; }
4.總結(jié)并整理宏和函數(shù)的區(qū)別
屬 性 | #define定義宏 | 函數(shù) |
代 碼 長 度 | 每次使用時(shí),宏代碼都會(huì)被 插入到程序中。除了非常小的宏之外,程序的長度會(huì)大幅度增長 | 函數(shù)代碼只出現(xiàn)于一個(gè)地方;每次使用這個(gè)函數(shù)時(shí),都調(diào)用那個(gè)地方的同一份代碼 |
執(zhí) 行 速 度 | 更快 | 存在函數(shù)的調(diào)用和返回的額外開銷,所以相對(duì)慢一些 |
操 作 符 優(yōu) 先 級(jí) | 宏參數(shù)的求值是在所有周圍表達(dá)式的上下文環(huán)境里,除非加上括號(hào),否則鄰近操作符的優(yōu)先級(jí)可能會(huì)產(chǎn)生不可預(yù)料的后果,所以建議宏在書寫的時(shí)候多些括號(hào)。 | 函數(shù)參數(shù)只在函數(shù)調(diào)用的時(shí)候求值一次,它的結(jié)果值傳遞給函數(shù)。表達(dá)式的求值結(jié)果更容易預(yù) 測(cè)。 |
帶 有 副 作 用 的 參 數(shù) | 參數(shù)可能被替換到宏體中的多個(gè)位置,所以帶有副作用的參數(shù)求值可能會(huì)產(chǎn)生不可預(yù)料的結(jié)果。 | 函數(shù)參數(shù)只在傳參的時(shí)候求值一 次,結(jié)果更容易控制。 |
參 數(shù) 類 型 | 宏的參數(shù)與類型無關(guān),只要對(duì)參數(shù)的操作是合法的, 它就可以使用于任何參數(shù)類型。 | 函數(shù)的參數(shù)是與類型有關(guān)的,如果參數(shù)的類型不同,就需要不同的函數(shù),即使他們執(zhí)行的任務(wù)是 不同的。 |
調(diào) 試 | 宏是不方便調(diào)試的 | 函數(shù)是可以逐語句調(diào)試的 |
遞 歸 | 宏是不能遞歸的 | 函數(shù)是可以遞歸的 |
5.有沒有宏和函數(shù)的結(jié)合體
答案是當(dāng)然有。
在C99和C++里面都有一個(gè)東西叫做內(nèi)聯(lián)函數(shù)(inline)
內(nèi)聯(lián)函數(shù)既有函數(shù)的優(yōu)點(diǎn)又有宏的優(yōu)點(diǎn):
- 宏的優(yōu)點(diǎn):內(nèi)聯(lián)函數(shù)沒有函數(shù)的調(diào)用和返回。
- 函數(shù)的優(yōu)點(diǎn): 內(nèi)聯(lián)函數(shù)本身是個(gè)函數(shù),它沒有參數(shù)優(yōu)先級(jí)、副作用等宏的缺點(diǎn)。
提示:由于本篇文章主要是講宏和函數(shù)的區(qū)別,內(nèi)聯(lián)函數(shù)就不多講,這里只做了解,后面我會(huì)單獨(dú)寫一篇文章來講解內(nèi)聯(lián)函數(shù)的。
二、宏和函數(shù)的命名約定
一般來講函數(shù)的宏的使用語法很相似。所以語言本身沒法幫我們區(qū)分二者。
那么我們平時(shí)就應(yīng)該有一個(gè)良好的書寫習(xí)慣:
把宏名全部大寫
函數(shù)名不要全部大寫
這里可以參考《高質(zhì)量C/C++編程指南》這本書,有興趣的小伙伴可以去看看。
到此這篇關(guān)于C/C++細(xì)數(shù)宏與函數(shù)有那些區(qū)別的文章就介紹到這了,更多相關(guān)C/C++宏與函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)串(堆分配存儲(chǔ)表示法)實(shí)例詳解
這篇文章主要介紹了C語言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)串(堆分配存儲(chǔ)表示法)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-07-07C++中靜態(tài)庫與動(dòng)態(tài)庫的使用示例
在C/C++中使用庫的技術(shù),庫主要分為兩種類型:靜態(tài)庫和動(dòng)態(tài)庫,本文主要介紹了C++中靜態(tài)庫與動(dòng)態(tài)庫的使用示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09C++采用openfilename打開文件對(duì)話框用法實(shí)例
這篇文章主要介紹了C++采用openfilename打開文件對(duì)話框用法實(shí)例,是C++文件操作中非常實(shí)用的技巧,需要的朋友可以參考下2014-10-10c語言conio.h基本知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家分享的是關(guān)于c語言conio.h是什么意思的相關(guān)知識(shí)點(diǎn),需要的朋友們可以學(xué)習(xí)參考下。2020-02-02vc中SendMessage自定義消息函數(shù)用法實(shí)例
這篇文章主要介紹了vc中SendMessage自定義消息函數(shù)用法,以實(shí)例實(shí)行詳細(xì)講述了SendMessage的定義、原理與用法,具有一定的實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10C++詳細(xì)分析lambda表達(dá)式的本質(zhì)
Lambda表達(dá)式是現(xiàn)代C++在C ++ 11和更高版本中的一個(gè)新的語法糖 ,在C++11、C++14、C++17和C++20中Lambda表達(dá)的內(nèi)容還在不斷更新。 lambda表達(dá)式(也稱為lambda函數(shù))是在調(diào)用或作為函數(shù)參數(shù)傳遞的位置處定義匿名函數(shù)對(duì)象的便捷方法2022-06-06