加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 一、宏和函數(shù)怎么選?
    • 二、預(yù)處理宏的優(yōu)缺點(diǎn)
    • 三、宏的缺陷,內(nèi)聯(lián)函數(shù)的引入
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

干貨 | 從宏和函數(shù)引出內(nèi)聯(lián)函數(shù)

2023/09/30
3322
閱讀需 7 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

一個(gè)宏定義看看你的 C語(yǔ)言級(jí)別。

今天我們來(lái)看一下利用宏定義編寫類似函數(shù)調(diào)用的方法和真實(shí)的函數(shù)有什么區(qū)別,來(lái)進(jìn)一步理解宏定義的應(yīng)用。

一、宏和函數(shù)怎么選?

首先來(lái)看一個(gè)例子:

#define N 2+2
void main()
{
int a = N * N;
printf( "a = %d", a);
}

這里,我們得理解宏的工作方式,它是在編譯器編譯代碼之前做的一個(gè)純文本的替換工作,因此,有時(shí)候簡(jiǎn)單宏替換的結(jié)果就會(huì)和我們預(yù)想的結(jié)果出現(xiàn)偏差。

比如上面的例子,我們預(yù)期 N 為 4,a=16,但實(shí)際結(jié)果卻為 a=8;原因在于宏的作用方式是傻瓜式的文本替換。

在編譯之前,編譯器首先將宏定義的文本替換到程序體中,這個(gè)替換是完全無(wú)腦的一個(gè)操作,看一下替換結(jié)果就知道了。

#define N 2+2
void main()
{
int a = 2 + 2 * 2 + 2;
printf( "a = %d", a);
}

這也就是我們上一篇文章中講到的,寫宏函數(shù)的時(shí)候一定要注意括號(hào)的應(yīng)用,多加括號(hào)一定是利大于弊的。

二、預(yù)處理宏的優(yōu)缺點(diǎn)

軟件開(kāi)發(fā)過(guò)程中,經(jīng)常有一些常用或者通用的功能或者代碼段,這些功能既可以寫成函數(shù),也可以封裝成為宏定義。那么究竟是用函數(shù)好,還是宏定義好?

我們還是看上一篇文章中引用的比較大小的例子:

#define MAX( a, b) ( (a) > (b) ? (a) : (b) )
//把它用函數(shù)來(lái)實(shí)現(xiàn):
int max( int a, int b)
{
return (a > b ? a : b);
}

如果我們?cè)诔绦蛑袑⒁褂帽容^大小的函數(shù),我們顯然會(huì)選用上面的宏定義,理由如下:

1 首先,函數(shù)調(diào)用會(huì)帶來(lái)額外的開(kāi)銷,他需要開(kāi)辟新的棧空間,記錄返回值,還需要將形參壓入棧中,函數(shù)返回時(shí)還需要釋放堆棧空間。
這樣的開(kāi)銷不僅會(huì)讓程序執(zhí)行效率變低,代碼量也會(huì)大大增加,因此使用上面的宏函數(shù)做文本替代就顯得更明智。

2 其次,函數(shù)的形參被聲明成了一個(gè)特定的類型,如例子中是 int,這樣如果我們軟件中需要使用浮點(diǎn)型的比較大小,我們就不得不重寫一個(gè)函數(shù),從這一點(diǎn)也可以看到宏函數(shù)的優(yōu)勢(shì)。
因?yàn)槭俏谋镜奶鎿Q,因此他與類型也沒(méi)有關(guān)系,不過(guò)類型不對(duì)應(yīng),會(huì)在編譯階段的時(shí)候報(bào)錯(cuò),這點(diǎn)還是具備利用價(jià)值的。

3 另外,還有一些任務(wù)根本無(wú)法用函數(shù)實(shí)現(xiàn),但是用宏定義卻很好實(shí)現(xiàn)。

比如參數(shù)類型沒(méi)法作為參數(shù)傳遞給函數(shù),但是可以把參數(shù)類型傳遞給帶參的宏。

看下面的例子:

#define MALLOC(n, type)((type ) malloc((n)sizeof(type)))

利用這個(gè)宏,我們就可以為任何類型分配一段我們指定的空間大小,并返回指向這段空間的指針。我們可以觀察一下這個(gè)宏確切的工作過(guò)程:

int *ptr;
ptr = MALLOC ( 5, int );
//將這宏展開(kāi)以后的結(jié)果:
ptr = (int *) malloc ((5) * sizeof(int));

這個(gè)例子是宏定義的經(jīng)典應(yīng)用之一,完成了函數(shù)不能完成的功能,但是宏定義也不能濫用,通常,如果相同的代碼需要出現(xiàn)在程序的幾個(gè)地方,更好的方法是把它實(shí)現(xiàn)為一個(gè)函數(shù)。

三、宏的缺陷,內(nèi)聯(lián)函數(shù)的引入

宏雖然有著一定的優(yōu)勢(shì),但是它的缺點(diǎn)也不可忽視。

在編譯階段,我們很難發(fā)現(xiàn)代碼哪里出問(wèn)題了,因?yàn)楹晏鎿Q是發(fā)生在預(yù)處理階段,所以有時(shí)候在宏函數(shù)傳參的時(shí)候發(fā)生一些錯(cuò)誤,編譯器不會(huì)發(fā)現(xiàn),那它調(diào)試起來(lái)就很麻煩。

所以為了解決這種不利于調(diào)試的問(wèn)題,就有了內(nèi)聯(lián)函數(shù)。

那么什么是內(nèi)聯(lián)函數(shù)呢?

我們以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯階段,C編譯器會(huì)在調(diào)用函數(shù)的地方直接把函數(shù)展開(kāi),沒(méi)有壓棧開(kāi)銷,內(nèi)聯(lián)函數(shù)提升程序運(yùn)行效率,但是會(huì)相應(yīng)的增加代碼的長(zhǎng)度。所以這里叫做空間換時(shí)間。

道之初,帶來(lái)了空間和時(shí)間,所以,空間和時(shí)間就是編程的陰陽(yáng)兩級(jí)。

不懂編程之道的程序員常常把空間和時(shí)間消耗殆盡,得道的程序員則總是有足夠的空間和時(shí)間完成編程任務(wù)。

舉個(gè)例子

inline int Add(int a,int b)
{
return a+b;
}

編譯期間,編譯器會(huì)將內(nèi)聯(lián)函數(shù)替換相應(yīng)的函數(shù)體;

這里要注意一點(diǎn),在函數(shù)前加 inline 只是建議編譯器當(dāng)作內(nèi)容函數(shù)處理 ,但編譯器有自己的主張(遞歸 ,復(fù)雜函數(shù)等)

內(nèi)聯(lián)函數(shù)的特性:

inline是一種以空間換時(shí)間的做法,省去調(diào)用函數(shù)中參數(shù)壓棧,減少了調(diào)用的開(kāi)銷。同時(shí),使用內(nèi)聯(lián)函數(shù)也比宏函數(shù)更省心,不必?fù)?dān)心宏參數(shù)傳遞過(guò)程中出現(xiàn)的意外情況。

inline對(duì)于編譯器而言只是一個(gè)建議,編譯器會(huì)自動(dòng)優(yōu)化,如果定義為inline的函數(shù)體內(nèi)有循環(huán)/遞歸等等,編譯器優(yōu)化時(shí)會(huì)忽略掉內(nèi)聯(lián),另外,如果內(nèi)聯(lián)函數(shù)的函數(shù)體過(guò)大,一般的編譯器也會(huì)放棄內(nèi)聯(lián)方式,采用普通調(diào)用的方式進(jìn)行函數(shù)調(diào)用。

inline不建議聲明和定義分離,分離會(huì)導(dǎo)致鏈接錯(cuò)誤。因?yàn)閕nline被展開(kāi),就沒(méi)有函數(shù)地址了,鏈接就會(huì)找不到。

推薦器件

更多器件
器件型號(hào) 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊(cè) ECAD模型 風(fēng)險(xiǎn)等級(jí) 參考價(jià)格 更多信息
FTLF8524P2BNV 1 Finisar Corporation Transceiver, 830nm Min, 860nm Max, 4250Mbps(Tx), 4250Mbps(Rx), LC Connector, Panel Mount, ROHS COMPLIANT PACKAGE
$301.6 查看
AFBR-5905Z 1 Agilent Technologies Inc Transceiver, Through Hole Mount,
$465.39 查看
PVT422SPBF 1 International Rectifier Transistor Output SSR, 2-Channel, 4000V Isolation, LEAD FREE, PLASTIC, SURFCAE MOUNT, DIP-8
$8.57 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

多年硬件從業(yè)經(jīng)驗(yàn),專注分享從研發(fā)到供應(yīng)鏈,再到精益制造過(guò)程中的經(jīng)驗(yàn)和感悟!