原文後面提到的東西愈來愈多,此篇一點一點慢慢討論,
沒 k 過 spec., 沒追過 assembly code,有誤請不吝指正。
先談 inline 的特性 , 再討論 static , 用大量的程式碼做輔助說明應該會清楚些。
另由於我手邊的 vs2010 要用 inline 就得用 cpp ,故暫時先以 c++ 的方式探討。
以下說的 "DEBUG MODE" 指的是沒有任何優化參數;
"RELEASE MODE" 指的是有下 -O2 優化參數。
壹、inline
的確一般的 inline function,實作和宣告會放在同一個檔案裡面,如下。
例 1.1 (correct)
// mymath.h
#pragma once
inline int inc(int a) { return a+1; }
// main.cpp
#include "mymath.h"
int main() { inc(1) ; return 0;}
若拆成 mymath.h / mymath.cpp 做的話,的確在 compile 時就會有語法上的錯誤
例 1.2 (error)
// mymath.h
#pragma once
inline int inc(int v);
// mymath.cpp
#include "mymath.h"
inline int inc(int v) { return v+1;}
// main.cpp
#include "mymath.h"
int main() { inc(1) ; return 0;}
inline 做的事情是 "建議" compiler 不要實際產生一個 function,
而是如你說的,像是用 macro 的方式在呼叫的地方做替換,但這件事是叫
"建議",而不是 "絕對"。而這個 "建議",通常在 Debug Mode 都是無效的,
這點不論 gcc 或 vs 都一樣。故在 MFC 的一些 src code 會透過 macro 進行
inline switch 作法,也就是在 Debug Mode 時,該函式不實作為 inline 函式;
在 Release Mode 時會實作為 inline 函式,所以 MFC src 會看到另一種副檔
名的 src code : XXXX.inl,讓人感覺很繞路,但會這麼做的原因是想讓
編譯速度加快,不過我沒測過時間就是。
上篇提到的的,compiler 強度可以決定要不要 inline,答案是沒錯的,
甚至我認為說不定未來 inline 關鍵字和 register 關鍵字走向一樣的結果,
在 Debug Mode 的時候基本上是完全不理會,一律用一般 function / variable
方式處理;在 Release Mode 也是忽視這二個識別字,因 user 要不要用
inline 或是 register 的建議,對 compiler 而言可能都很爛,還不如讓
compiler 自己做就好。這也是為什麼 vs release mode 下中斷點,有些變數
看不到、有些函式進不去的原因 (因都被優化掉了)。
貮、static
回到 mymath 問題,但若今天的情況是,我在實作 mymath 的所有對外
functions (像是 mysin, mycos, mytan... 等讓其他 coder 使用的),
並不打算讓其他 coder 在引入 mymath.h 時可以用到 inc 時,我的
inc 就不想放在 mymath.h 裡面,只想實作在 mymath.cpp 裡,且考慮
到 inc 較適合用 inline,情況就變如下
例 2.1
// mymath.h
#pragma once
double mysin(double x);
double mycos(double x);
// mymath.cpp
#include "mymath.h"
inline int inc(int v) { return v+1;}
double mysin(double x){...}
double mycos(double x){...}
一般 "正常使用" , 沒有人在 main.cpp 做 extern 時, Release Mode 下
inc 會被做 inline 沒錯,但若今天有人無聊,想在 main.cpp 中,hack
到 mymath.cpp 裡面的 inc 時,情況就不一樣了。
例 2.2
// main.cpp
#include "mymath.h"
extern int inc(int v);
int main() { inc(1) ; return 0;}
這時由於 inc function 在其他檔案 extern 出來,在 mymath.cpp 裡的 inc
就不會被用 inline 內崁在程式碼裡,但 extern inline 這特性說真的,主要
還是看 compiler 有沒有能力再做 inline。為了避免我原本不想開放、要 inline 的
東西被亂搞,搞成不能變 inline,就在 mymath.cpp 裡的 inc
變成 static inline 修飾,讓其他人沒辦法用 extern 抽出來。如下。
例 2.3
// mymath.h
#pragma once
double mysin(double x);
double mycos(double x);
// mymath.cpp
#include "mymath.h"
static inline int inc(int v) { return v+1;}
double mysin(double x){...}
double mycos(double x){...}
// main.cpp
#include "mymath.h"
extern int inc(int v);
int main() { inc(1) ; return 0;} // 這裡會報 error, 不讓人亂搞
~~~~~~
以上,故事有點長,若敘述有誤,請不吝指正。
謝謝收聽。