推 littleshan:最後,inline這個關鍵字是為了C++這種分離.h的語言而設10/25 22:19
→ littleshan:像c#或java這種界面和實作寫在一起的語言10/25 22:20
→ littleshan:編譯的時候compiler有足夠的資訊自行判斷是否要inline10/25 22:20
→ littleshan:所以沒必要另外要求programmer手動標示10/25 22:21
推 littleshan:另一方面,C++ compiler在閱讀.h時,並不知道這是個.h10/25 22:27
→ littleshan:(因為compiler讀進來的是經過preprocessor的處理結果)10/25 22:27
→ littleshan:所以有必要透過inline來標示函式為weak linkage10/25 22:29
謝謝前面 t 大,以及樓上 littleshan 前輩的回應。
小弟書唸得太少,看完好像還是有點混亂,發文提出自己的理解與版友們探討。
就我的認知,inline 函數的主要目的,是為了節省函數調用時的轉換時間。
比如從 main 函數要調用函數 foo 時,需先從 main 的 stack frame 切換至 foo,
然後才真的開始做計算,做完計算又要切換回原本 main 的 stack frame。
若 foo 的計算內容可直接在 main 裡計算,那就能將 foo 定為 inline 來省時間。
那假設有 src1.cpp 與 src2.cpp 兩個檔,他們都用到 inline function foo,
此時將 foo 的函數定義放在 src1.cpp 或 src2.cpp 都不對。
因為 C++ 編譯器 (以 VC 為例),一次處理一個原始碼檔案,
如果定義只寫在 src2.cpp,那在編譯 src1.cpp 時就沒辦法將 foo 的內容展開。
所以 foo 的函數定義必須在 src1.cpp 與 src2.cpp 裡都有出現。
而為了容易維護,所以將 foo 定義於 .h 檔裡,透過這種手段來達到兩個 cpp 檔裡
都有 foo 定義內容。但寫在 .h 檔不是必要做法,只是比較好維護。
小弟不懂的是像 JAVA
檔案 Myin.java 內容:
======================================================
public class Myin {
public static void main(String[] args) {
System.out.println("Hello");
Myout.foo();
}
}
======================================================
檔案 Myout.java 內容:
======================================================
public class Myout {
public static void foo() {
System.out.println("Myout.foo is called.");
}
}
======================================================
執行 javac.exe Myin.java 得到 Myin.class
執行 javac.exe Myout.java 得到 Myout.class
執行 java Myin 輸出
Hello
Myout.foo is called.
那這邊 javac Myin.java 有點像 cl.exe src1.cpp 的狀況,其函數 foo 的定義
是在另外一個原始碼檔案,那 JAVA 又怎麼有辦法判斷 foo 不應該用函數調用的方式
而應該用 inline 的方式去執行來節省函數調用的時間呢?
無知的問題,請各位見諒...
###########################################
2011/10/26 00:56 補充
討論一下 inline 把函數 foo 變成「弱符號」來避開 src1.cpp 及 src2.cpp 內
有 foo 重複定義這件事。
想到之前有人討論 VC 有沒有類似 GCC 的 __attribute__((weak)) 功能。
來回味順便補充到這篇文章。
檔案 1.cpp
=======================
#include <stdio.h>
#include "blah.h"
void fun(void);
int main() {
blah();
fun();
return 0;
}
========================
檔案 2.cpp
========================
#include <stdio.h>
#include "blah.h"
void fun(void) {
printf("fun is called.\n");
blah();
}
========================
檔案 blah.h
========================
#include <stdio.h>
void blah(void) {
printf("blah is called.\n");
}
========================
用 GCC 編譯:gcc 1.cpp 2.cpp -o gcc1.exe
會回報錯誤 multiple definition of `blah()'
用 VC 編譯:cl 1.cpp 2.cpp
會回報錯誤 error LNK2005: "void __cdecl blah(void)" (?blah@@YAXXZ) 已
在 1.obj 中定義過了
因為按照預設的規則 blah 函數是強符號,所以不能有重複的定義。
此時可以用 inline 關鍵字,去除這個囧況:
inline void blah(void) {
printf("blah is called.\n");
}
不管是 VC 或 GCC 都能編譯成功,執行結果為
blah is called.
fun is called.
blah is called.
如果把檔名改成 1.c 跟 2.c 則因為 C 語言沒有 inline,所以會編譯失敗,
但在 VC 可以改成如下來達到同樣效果。
__inline void blah(void) {
printf("blah is called.\n");
}
但 inline 的做法,會使得 blah 的實作內容在 1.cpp 與 2.cpp 的目的檔
裡面重複出現。所以 GCC 提供 __attribute__((weak)) 語法可以不必跑 inline
的路線,但又能達到將 foo 變成弱符號的效果。
也就是說將 blah.h 的內容改成如下即可
======================
#include <stdio.h>
__attribute__((weak)) void blah(void) {
printf("blah is called.\n");
}
======================
但是 VC 不支援類似的語法,依造這個網頁的 Walkarounds 所述:
http://tinyurl.com/3odwcg6
改成如下就可以有 GCC 的 __attribute__((weak)) 效果:
======================
#include <stdio.h>
__declspec(noinline) __inline void blah(void) {
printf("blah is called.\n");
}
======================
其思路還是利用 inline 先達到弱符號化的效果,而且使用微軟的 __inline (在 C/C++
都能用),然後再利用奇特的 __declspec(noinline) 微軟獨創宣告,
告訴編譯器不要把此函數當成 inline function 去展開處理
(__declspec(noinline) tells the compiler to never inline a particular member
function (function in a class).)
蠻莫名其妙的搭配。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 124.8.135.93
→ james732:剛剛看了一下,Java只會在runtime的時候由JVM做inline 10/25 23:42
→ james732:編譯的時候不會做,所以那行javac並不管這個 10/25 23:43
→ imprazaguy:這是個好問題,我從沒想過 10/25 23:47
→ james732:Java和C#這種VM的語言,在runtime時做的事情好像很多... 10/25 23:50
→ poyenc:以上出處 14882:2011 7.1.2 10/25 23:52
→ purpose:瞭解,感謝。難怪現在虛擬機器越來越流行 10/25 23:58
推 littleshan:no,這和VM其實沒關係,而是語言設計上的不同 10/26 00:10
→ diabloevagto:C++給予的權限較多,相對於java是內部自行處理的 10/26 00:11
→ bernachom:我記得用inline,程式有時後也不見得會執行? 10/26 00:17
推 tropical72:是給建議沒錯,有些compiler甚至無視inline,所有inline 10/26 00:19
→ tropical72:都自己調。 10/26 00:19
推 littleshan:對,inline只是提示,compiler可以自行決定要不要展開 10/26 00:19
→ diabloevagto:只是建議沒錯,但至少有給個機會... 10/26 00:19
→ bernachom:不知道compiler給機會的條件是什麼@@.... 10/26 00:20
→ poyenc:你沒開最佳化或加選項, 基本上等於沒機會 10/26 00:20
→ bernachom:我手邊的書裡好像沒寫到這回事.. 10/26 00:20
→ tropical72:occurs only if the compiler's cost/benefit 10/26 00:24
→ tropical72:analysis show it to be profitable. 10/26 00:24
推 littleshan:是否展開會和function內容有關 10/26 00:24
→ bernachom:如果太多行,我想也不會展開才是,應該就是和function有 10/26 00:25
→ bernachom:關了~ 10/26 00:26
→ diabloevagto:想請問,compiler會自動判斷,那是否就交給compiler 10/26 00:29
→ diabloevagto:決定就好?我們不用再多決定呢? 10/26 00:30
推 tropical72:那要看compiler 有沒有支援,及參數怎麼下,同時必需堅 10/26 00:34
→ tropical72:信 compiler 判斷是正確的, 以 VC 為例,參數在 /Obn, 10/26 00:34
→ diabloevagto:感謝指教! 10/26 00:41
※ 編輯: purpose 來自: 124.8.135.93 (10/26 01:25)
→ poyenc:C99 有 inline 10/26 01:43
推 tropical72:傳說中的 weak function ... 10/26 01:52