6-3 宏定義
發表時(shí)間:2020-10-19
發布人(rén):融晨科技
浏覽次數:64
6.3.1 宏定義的(de)規則和(hé / huò)使用解析
(1)宏定義的(de)解析規則就(jiù)是(shì):在(zài)預處理階段由預處理器來(lái)進行替換,這(zhè)個(gè)替換是(shì)原封不(bù)動的(de)替換。
(2)宏定義替換會遞歸進行,直到(dào)替換出(chū)來(lái)的(de)值本身不(bù)再是(shì)一個(gè)宏爲(wéi / wèi)止。
(3)一個(gè)正确的(de)宏定義式子(zǐ)本身分爲(wéi / wèi)3部分:第一部分是(shì)#define,第二部分是(shì)宏名,剩下的(de)爲(wéi / wèi)第三部分。
(4)宏可以(yǐ)帶參數,稱爲(wéi / wèi)帶參宏。帶參宏的(de)使用和(hé / huò)帶參函數非常像,但是(shì)使用上(shàng)有一些差異。在(zài)定義帶參宏時(shí),每一個(gè)參數在(zài)宏體中引用時(shí)都必須加括号,最後整體再加括号,括号缺一不(bù)可。
#include <stdio.h>
#define X(a,b) ((a)+(b))
int main()
{
int a = 1,b = 2;
int c =3 * X(a,b);
printf("c = %d\n",c);
return 0;
}
6.3.2 宏定義示例1:MAX,求2個(gè)數中較大(dà)的(de)一個(gè)
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
關鍵:
第一點:要(yào / yāo)想到(dào)使用三目運算符來(lái)完成。
第二點:注意括号的(de)使用。
6.3.3 宏定義示例2:SEC_PER_YEAR,用宏定義表示一年有多少秒
#define SEC_PER_YEAR (365*24*60*60UL)
關鍵:
第一點:當一個(gè)數字直接出(chū)現在(zài)程序中時(shí),它的(de)類型默認是(shì)int;
第二點:一年有多少秒,這(zhè)個(gè)數字剛好超過了(le/liǎo)int類型存儲的(de)範圍
6.3.4 帶參宏和(hé / huò)帶參函數的(de)區别(宏定義的(de)缺陷)
(1)宏定義是(shì)在(zài)預處理期間處理的(de),而(ér)函數是(shì)在(zài)編譯期間處理的(de)。這(zhè)個(gè)區别帶來(lái)的(de)實質差異是(shì):宏定義最終是(shì)在(zài)調用宏的(de)地(dì / de)方把宏體原地(dì / de)展開,而(ér)函數是(shì)在(zài)調用函數處跳轉到(dào)函數中去執行,執行完後再跳轉回來(lái)。
注意:宏定義和(hé / huò)函數的(de)最大(dà)差别就(jiù)是(shì):宏定義是(shì)原地(dì / de)展開,因此沒有調用開銷;而(ér)函數是(shì)跳轉執行再返回,因此函數有比較大(dà)的(de)調用開銷。所以(yǐ)宏定義和(hé / huò)函數相比,優勢就(jiù)是(shì)沒有調用開銷,沒有傳參開銷,所以(yǐ)當函數體很短(尤其是(shì)隻有一句話時(shí))可以(yǐ)用宏定義來(lái)替代,這(zhè)樣效率比較高。
(2)帶參宏和(hé / huò)帶參函數的(de)一個(gè)重要(yào / yāo)差别就(jiù)是(shì):宏定義不(bù)會檢查參數的(de)類型,返回值也(yě)不(bù)會附帶類型;而(ér)函數有明确的(de)參數類型和(hé / huò)返回值類型。當我們調用函數時(shí)編譯器會幫我們做參數的(de)靜态類型檢查,如果編譯器發現我們實際傳參和(hé / huò)參數聲明不(bù)同時(shí)會報警告或錯誤。
注意:用函數的(de)時(shí)候程序員不(bù)太用操心類型不(bù)匹配,因爲(wéi / wèi)編譯器會檢查,如果不(bù)匹配編譯器會叫;用宏的(de)時(shí)候程序員必須很注意實際傳參和(hé / huò)宏所希望的(de)參數類型一緻,否則可能編譯不(bù)報錯但是(shì)運行有誤。
總結:宏和(hé / huò)函數各有千秋,各有優劣。總的(de)來(lái)說(shuō),如果代碼比較多用函數适合而(ér)且不(bù)影響效率;但是(shì)對于(yú)那些隻有一兩句話的(de)函數開銷就(jiù)太大(dà)了(le/liǎo),适合用帶參宏。但是(shì)用帶參宏又有缺點:不(bù)檢查參數類型。
6.3.5 内聯函數和(hé / huò)inline關鍵字
(1)内聯函數通過在(zài)函數定義前加inline關鍵字實現。
(2)内聯函數本質上(shàng)是(shì)函數,所以(yǐ)有函數的(de)優點(内聯函數是(shì)編譯器負責處理的(de),編譯器可以(yǐ)幫我們做參數的(de)靜态類型檢查);但是(shì)它同時(shí)也(yě)有帶參宏的(de)優點(不(bù)用調用開銷,而(ér)是(shì)原地(dì / de)展開)。所以(yǐ)幾乎可以(yǐ)這(zhè)樣認爲(wéi / wèi):内聯函數就(jiù)是(shì)帶了(le/liǎo)參數靜态類型檢查的(de)宏。
(3)當我們的(de)函數内函數體很短(譬如隻有一兩句話)的(de)時(shí)候,我們又希望利用編譯器的(de)參數類型檢查來(lái)排錯,我還希望沒有調用開銷時(shí),最适合用内聯函數。
6.3.6 宏定義來(lái)實現條件編譯(#define #undef #ifdef)
(1)程序有DEBUG和(hé / huò)RELEASE版本,區别就(jiù)是(shì)編譯時(shí)有無定義DEBUG宏。
#include <stdio.h>
//這(zhè)兩行代碼的(de)效果加在(zài)一起就(jiù)相當于(yú)沒有定義DEBUG
//注銷一個(gè)宏。如果前面有定義這(zhè)個(gè)宏則取消這(zhè)個(gè)宏,如果沒有就(jiù)無視掉
#define DEBUG
#undef DEBUG
#ifdef DEBUG
#define debug(x) printf(x)
#else
#define debug(x)
#endif
int main(void)
{
debug("this is a debug info\n");
return 0;
}