C語言中的內(nèi)聯(lián)函數(shù)(inline)與宏定義(#define)詳細解析
先簡明扼要,說下關鍵:
1、內(nèi)聯(lián)函數(shù)在可讀性方面與函數(shù)是相同的,而在編譯時是將函數(shù)直接嵌入調(diào)用程序的主體,省去了調(diào)用/返回指令,這樣在運行時速度更快。
2、內(nèi)聯(lián)函數(shù)可以調(diào)試,而宏定義是不可以調(diào)試的。
內(nèi)聯(lián)函數(shù)與宏本質上是兩個不同的概念如果程序編寫者對于既要求快速,又要求可讀的情況下,則應該將函數(shù)冠以inline。下面詳細介紹一下探討一下內(nèi)聯(lián)函數(shù)與宏定義。
一、內(nèi)聯(lián)函數(shù)是什么?
內(nèi)聯(lián)函數(shù)是代碼被插入到調(diào)用者代碼處的函數(shù)。如同 #define 宏(但并不等同,原因見下文),內(nèi)聯(lián)函數(shù)通過避免被調(diào)用的開銷來提高執(zhí)行效率,尤其是它能夠通過調(diào)用(“過程化集成”)被編譯器優(yōu)化。
二、 內(nèi)聯(lián)函數(shù)是如何在安全和速度上取得折衷?
在 C 中,你可以通過在結構中設置一個 void* 來得到“封裝的結構”,在這種情況下,指向實際數(shù)據(jù)的 void* 指針對于結構的用戶來說是未知的。因此結構的用戶不知道如何解釋void*指針所指內(nèi)容,但是存取函數(shù)可以將 void* 轉換成適當?shù)碾[含類型。這樣給出了封裝的一種形式。
不幸的是這樣做喪失了類型安全,并且也將繁瑣的對結構中的每個域的訪問強加于函數(shù)調(diào)用。(如果你允許直接存取結構的域,那么對任何能直接存取的人來說,了解如何解釋 void* 指針所指內(nèi)容就是必要的了;這樣將使改變底層數(shù)據(jù)結構變的困難)。
雖然函數(shù)調(diào)用開銷是很小的,但它會被累積。C++類允許函數(shù)調(diào)用以內(nèi)聯(lián)展開。這樣讓你在得到封裝的安全性時,同時得到直接存取的速度。此外,內(nèi)聯(lián)函數(shù)的參數(shù)類型由編譯器檢查,這是對 C 的 #define 宏的一個改進。
三、為什么我應該用內(nèi)聯(lián)函數(shù)?而不是原來清晰的 #define 宏?
因為#define宏定義函數(shù)是在四處是有害的:
和 #define 宏不同的是,內(nèi)聯(lián)函數(shù)總是對參數(shù)只精確地進行一次求值,從而避免了那聲名狼藉的宏錯誤。換句話說,調(diào)用內(nèi)聯(lián)函數(shù)和調(diào)用正規(guī)函數(shù)是等價的,差別僅僅是更快:
// 返回 i 的絕對值的宏
#define unsafe(i) \
( (i) >= 0 ? (i) : -(i) )
// 返回 i 的絕對值的內(nèi)聯(lián)函數(shù)
inline
int safe(int i)
{
return i >= 0 ? i : -i;
}
int f();
void userCode(int x)
{
int ans;
ans = unsafe(x++); // 錯誤!x 被增加兩次
ans = unsafe(f()); // 危險!f()被調(diào)用兩次
ans = safe(x++); // 正確! x 被增加一次
ans = safe(f()); // 正確! f() 被調(diào)用一次
}
和宏不同的,還有內(nèi)聯(lián)函數(shù)的參數(shù)類型被檢查,并且被正確地進行必要的轉換。宏定義復雜函數(shù)是有害的;非萬不得已不要用。
四、如何告訴編譯器使非成員函數(shù)成為內(nèi)聯(lián)函數(shù)?
聲明內(nèi)聯(lián)函數(shù)看上去和普通函數(shù)非常相似:
void f(int i, char c);
當你定義一個內(nèi)聯(lián)函數(shù)時,在函數(shù)定義前加上 inline 關鍵字,并且將定義放入頭文件:inlinevoid f(int i, char c){ // ...}
注意:將函數(shù)的定義({...}之間的部分)放在頭文件中是強制的,除非該函數(shù)僅僅被單個 .cpp 文件使用。尤其是,如果你將內(nèi)聯(lián)函數(shù)的定義放在 .cpp 文件中并且在其他 .cpp文件中調(diào)用它,連接器將給出 “unresolved external” 錯誤。
五、如何告訴編譯器使一個成員函數(shù)成為內(nèi)聯(lián)函數(shù)?
聲明內(nèi)聯(lián)成員函數(shù)看上去和普通函數(shù)非常類似:
class Fred {public:
void f(int i, char c);};
但是當你定義內(nèi)聯(lián)成員函數(shù)時,在成員函數(shù)定義前加上 inline 關鍵字,并且將定義放入頭文件中:inlinevoid Fred::f(int i, char c){ // ...}通常將函數(shù)的定義({...}之間的部分)放在頭文件中是強制的。如果你將內(nèi)聯(lián)函數(shù)的定義放在 .cpp 文件中并且在其他 .cpp 文件中調(diào)用它,連接器將給出“unresolved external”錯誤。
六、 有其它方法告訴編譯器使成員函數(shù)成為內(nèi)聯(lián)嗎?
有:在類體內(nèi)定義成員函數(shù):class Fred {public: void f(int i, char c) { // ... }};盡管這對于寫類的人來說很容易,但由于它將類是“什么”(what)和類“如何”(how)工作混在一起.小結總之,在嵌入式C(或C++)編程里面,懂得使用內(nèi)聯(lián)函數(shù)(inline)與宏定義(#define),并使用好它們,對我們是大有裨益的。(注:本文部分內(nèi)容來源于網(wǎng)絡整理,上述探討屬于個人意見,僅供參考。錯誤之處也是難免!)
欄 目:C語言
下一篇:C/C++ 宏詳細解析
本文標題:C語言中的內(nèi)聯(lián)函數(shù)(inline)與宏定義(#define)詳細解析
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/4108.html
您可能感興趣的文章
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用函數(shù)刪除字符
- 04-02c語言的正則匹配函數(shù) c語言正則表達式函數(shù)庫
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對數(shù)怎么表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段函數(shù)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排序法函數(shù)
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段函數(shù)
- 04-02C語言中怎么打出三角函數(shù) c語言中怎么打出三角函數(shù)的值
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求階乘


閱讀排行
本欄相關
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機閱讀
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10C#中split用法實例總結
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11ajax實現(xiàn)頁面的局部加載