在 C# CLR 中學習 C++ 之瞭解 namespace

2022-09-01 15:03:31

一:背景

相信大家在分析 dump 時,經常會看到 WKSSRV 這樣的字眼,如下程式碼所示:


00007ffa`778a07b8 coreclr!WKS::gc_heap::segment_standby_list = 0x00000000`00000000
00007ffa`778a3870 coreclr!WKS::qpf = 0x989680
00007ffa`7789da30 coreclr!SVR::heap_select::numa_node_to_heap_map = unsigned short [1028]
00007ffa`7789f2d0 coreclr!SVR::gc_heap::should_expand_in_full_gc = 0n0

其實這就是名稱空間,即 coreclr 在編譯原始碼的時候,為 WKSSVR 各編譯了一份,不知道這麼做的初衷是什麼,這裡就不管了,接下來看下 coreclr 中大概長啥樣子。


namespace WKS {
    #include "gcimpl.h"
    #include "gc.cpp"
}

namespace SVR {
    #include "gcimpl.h"
    #include "gc.cpp"
}

二:聊一聊 namespace

其實和 C# 的 namespace 本質差不多,都是起到隔離的作用,而且和 using 的配合使用和 C# 也是如出一轍,太有意思了。

1. 簡單的隔離

在 C++ 中預設只有一個 namespace,所以相同的變數會出現衝突,解決辦法就是用 namespace 隔離,參考如下程式碼:


namespace WKS
{
	int a = 10;
	int b = 11;
}

namespace SRV {

	int a = 100;
	int b = 101;
}

int main()
{
	printf("WKS::a= %d \n", WKS::a);
	printf("SRV::a= %d \n", SRV::a);
}

當然還可以巢狀使用,比如改成這樣。


namespace WKS
{
	namespace V1 {
		int a = 10;
		int b = 11;
	}
}

int main()
{
	printf("WKS::a= %d \n", WKS::V1::a);
}

接下來看下組合程式碼:

哈哈,看到上面的 WKS::V1::a 感覺是不是挺舒服的,也特能理解目前的 coreclr!WKS::xxx 了, 不過這裡有一個麻煩的地方,就是每次用 a 的時候都要輸入很長的字首,那有沒有簡化的方法呢? 當然有啦。

2. 使用 using 匯入

接下來我們用 using 直接在 main 函數中定義欄位,後續就不需要再寫長長的字首參照了,參考程式碼如下:


namespace WKS
{
	namespace V1 {
		int a = 10;
		int b = 11;
	}
}

int main()
{
	using WKS::V1::a;

	printf("WKS::V1::a1= %d \n", a);
}

3. 使用 using 定義別名

定義別名這功能特別好,個人感覺已經完全替代以前的 typedef 功能,比如下面的程式碼是完全一樣的。


int main()
{
	typedef const char* PCHAR;

	using PCHAR2 = const char*;

	PCHAR ptr1 = "hello world1";

	PCHAR2 ptr2 = "hello world2";
}

如果還不信的話,可以看下它們各自生成的組合程式碼。


	PCHAR ptr1 = "hello world1";
00007FF79856183B  lea         rax,[string "hello world1" (07FF798569C10h)]  
00007FF798561842  mov         qword ptr [ptr1],rax  

	PCHAR2 ptr2 = "hello world2";
00007FF798561846  lea         rax,[string "hello world2" (07FF798569CE8h)]  
00007FF79856184D  mov         qword ptr [ptr2],rax  

4. 使用 using namespace 匯入

這個是最普遍的,我們對系統庫的呼叫,無一不是用 using namespace 方式的,比如下面的程式碼。


using namespace std;

int main()
{
	string str = "hello world";
}

接下來我們把 V1 匯入到 main 方法中,這樣就可以自由自在的使用 WKS::V1 中的內容了,參考如下程式碼:


namespace WKS
{
	namespace V1 {
		int a = 10;
		int b = 11;
	}
}

int main()
{
	using namespace WKS::V1;

	printf("a=%d, b=%d", a, b);
}

好了,這就是對 namespace 的一點理解,本篇就說這麼多吧,希望對你有幫助。