在 CLR 原始碼中有很多的 extern
和 extern "C"
這樣的關鍵詞,比如下面這些程式碼:
extern size_t gc_global_mechanisms[MAX_GLOBAL_GC_MECHANISMS_COUNT];
extern DWORD g_dwHandles;
// The single GC heap instance, shared with the VM.
extern IGCHeapInternal* g_theGCHeap;
extern PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntimeFunction, /* out */ SIZE_T * pSize);
extern "C" uint32_t* g_gc_card_table;
extern "C" uint8_t* g_gc_lowest_address;
extern "C"
{
uint8_t *g_gc_sw_ww_table = nullptr;
bool g_gc_sw_ww_enabled_for_gc_heap = false;
}
那這些都是什麼意思呢? 為了更好的學習 CLR,這些還是要簡單瞭解一下的。
在 C# 中並沒有聽說過有 extern
這種概念,其實變數可以有兩種方式存在。
變數定義
變數參照
變數定義概念很簡單,定義就得給它分配記憶體空間,比如下面這樣:
#include <iostream>
#include <Windows.h>
int k = 10;
const char* ch = "abcde";
int main()
{
printf("ch=%d", strlen(ch));
}
接下來看下 變數參照
,它其實和 檔案參照
以及 C# 的 using
概念相似,即把其他檔案中的變數引入到本檔案,目的就是為了使用,比如在 Arts
檔案下定義了一個 page.cpp
檔案,截圖如下:
為了能夠在 ConsoleApplication3.cpp
中使用 int i
,那怎麼辦呢? 這時候就需要用 extern 引入了。
因為 VisualStudio 可以幫我們自動連結,所以這裡就不需要 #include "page.cpp"
匯入,接下來把程式跑起來,就可以觀察到程式的結果。
如果不用 extern
匯入的話,就會出現編譯錯誤,說 n
是未定義的。
還有一點要注意 extern
是對外部變數的一個參照,它不會生成任何組合程式碼。
要理解這個關鍵詞,首先要明白 方法符號
的概念,因為 C 和 C++ 在給方法生成符號的邏輯是不一樣的,比如同樣的一個 fly
函數。
#include <stdio.h>
void fly() {
printf("hello world");
}
int main()
{
}
在 C 中生成的函數名還是 fly
字樣。
可 C++ 不這麼認為,它會對 fly 函數名重新編排,比如下面的 ?fly@@YAXXZ
。
如果你在 C++ 中混用 C 的話,這時候就有理念衝突,那在C++
中讓某些函數名還是原樣生成有辦法嗎?當然可以了,這就需要使用 extern "C"
,參考如下程式碼:
// page.cpp
#include <stdio.h>
extern "C"
{
void fly() {
printf("hello");
}
}
void fly2() {
printf("hello");
}
然後可以在 ConsoleApplication.cpp
中引入進來。
// ConsoleApplication.cpp
#include <iostream>
extern "C" void fly();
extern void fly2();
int main()
{
fly();
fly2();
return 0;
}
好了,本篇就簡單說這麼多吧,相信再回頭看 CLR 中的那些 extern 關鍵詞,你會有一些新的理解。