[問題] inline 的內部運作疑惑
推
10/25 22:19,
10/25 22:19
→
10/25 22:20,
10/25 22:20
→
10/25 22:20,
10/25 22:20
→
10/25 22:21,
10/25 22:21
推
10/25 22:27,
10/25 22:27
→
10/25 22:27,
10/25 22:27
→
10/25 22:29,
10/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
→
10/25 23:42, , 1F
10/25 23:42, 1F
→
10/25 23:43, , 2F
10/25 23:43, 2F
→
10/25 23:43, , 3F
10/25 23:43, 3F
→
10/25 23:47, , 4F
10/25 23:47, 4F
→
10/25 23:50, , 5F
10/25 23:50, 5F
→
10/25 23:50, , 6F
10/25 23:50, 6F
→
10/25 23:52, , 7F
10/25 23:52, 7F
→
10/25 23:58, , 8F
10/25 23:58, 8F
推
10/26 00:10, , 9F
10/26 00:10, 9F
→
10/26 00:11, , 10F
10/26 00:11, 10F
→
10/26 00:17, , 11F
10/26 00:17, 11F
推
10/26 00:19, , 12F
10/26 00:19, 12F
→
10/26 00:19, , 13F
10/26 00:19, 13F
推
10/26 00:19, , 14F
10/26 00:19, 14F
→
10/26 00:19, , 15F
10/26 00:19, 15F
→
10/26 00:20, , 16F
10/26 00:20, 16F
→
10/26 00:20, , 17F
10/26 00:20, 17F
→
10/26 00:20, , 18F
10/26 00:20, 18F
推
10/26 00:23, , 19F
10/26 00:23, 19F
→
10/26 00:24, , 20F
10/26 00:24, 20F
→
10/26 00:24, , 21F
10/26 00:24, 21F
推
10/26 00:24, , 22F
10/26 00:24, 22F
→
10/26 00:25, , 23F
10/26 00:25, 23F
→
10/26 00:26, , 24F
10/26 00:26, 24F
→
10/26 00:29, , 25F
10/26 00:29, 25F
→
10/26 00:30, , 26F
10/26 00:30, 26F
推
10/26 00:34, , 27F
10/26 00:34, 27F
→
10/26 00:34, , 28F
10/26 00:34, 28F
→
10/26 00:35, , 29F
10/26 00:35, 29F
→
10/26 00:41, , 30F
10/26 00:41, 30F
※ 編輯: purpose 來自: 124.8.135.93 (10/26 01:25)
→
10/26 01:43, , 31F
10/26 01:43, 31F
推
10/26 01:52, , 32F
10/26 01:52, 32F
討論串 (同標題文章)
以下文章回應了本文:
完整討論串 (本文為第 1 之 3 篇):