原文后面提到的东西愈来愈多,此篇一点一点慢慢讨论,
没 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, 不让人乱搞
~~~~~~
以上,故事有点长,若叙述有误,请不吝指正。
谢谢收听。