1.為何要有unsafe
也許是為了實現CLR類型安全的目標吧,默認情況下,C#沒有提供指針的使用算法,但是有些情況下也可能需要指針這樣直接訪問內存的東西(雖然目前我還沒有用過),但是有時候程序員非常清楚程序的運行狀況,需要使用指針直接訪問內存以便於提高性能或者調試、監控程序運行的內存的使用狀況,以便於采取相應的措施。還有一些情況是當我們需要調用外面DLL中的函數又不能使用DllImport 時,也需要指針來傳遞這些函數。
2.unsafe 的定義
MSDN:unsafe 關鍵字表示不安全上下文,該上下文是任何涉及指針的操作所必需的。
其實,意思就是要使用指針前,請用unsafe 聲明下,可以使類、方法,成員,類全局變量和代碼段,但不能修飾成員函數內部的局部變量,具體為什么不清楚,還望大神指點。
在使用unsafe之前,我們必須先看一段MSDN的話:在公共語言運行時 (CLR) 中,不安全代碼是指無法驗證的代碼。 C# 中的不安全代碼不一定是危險的;只是其安全性無法由 CLR 進行驗證的代碼。 因此,CLR 只對在完全受信任的程序集中的不安全代碼執行操作。 如果使用不安全代碼,由您負責確保您的代碼不會引起安全風險或指針錯誤。
因此,我們在運行unsafe 代碼是要在項目屬性-生成選項里配置下"允許運行不安全代碼"。先看下簡單的例子:
1 unsafe static void ChangeValue(int* pData) 2 { 4 *pData = 200; //修改所在地址值 6 } 7 8 9 unsafe static void Main() 10 { 12 int data = 100; 13 Console.WriteLine("原始值: {0}", data); 14 ChangeValue(&data); //取data地址並傳遞 15 Console.WriteLine("改變地址后: {0}", data); 16 17 Console.ReadLine(); 18 }
程序輸出:
原始值:100
修改地址后:200
3、引入fixed
當我們討論fixed的時候,不得不先了解下,托管代碼和非托管代碼,所謂托管代碼就是由CLR去執行的代碼而不是操作系統去執行的代碼,而非托管代碼就是繞過CLR,由操作系統直接執行,它有自己的垃圾回收、類型安全檢查等服務。
而不安全代碼就是允許自己使用指針訪問內存,但同時又要使用CLR提供的垃圾回收機制、類型安全檢查等服務,有的資料認為是介於CLR和非托管代碼之間的一種代碼運行機制,也可以理解。
正因為如此,我們自定義的指針地址就有可能被CLR垃圾回收機制重新調整位置,所以就引入了fixed ,MSDN對fixed的解釋是:fixed 語句設置指向托管變量的指針,並在執行該語句期間"固定"此變量。這樣就可以防止變量的重定位。
看下代碼的演示:
1 class PointerDemo 3 { 5 public int x, y; 7 }
11 class Program 13 { 15 unsafe static void ChangeValue(int* x, int* y) 17 { 19 *x = 200; //修改所在地址值 21 *y = 300; 23 }
27 unsafe static void Main() 29 { 31 var obj = new PointerDemo(); 33 Console.WriteLine("原始值: {0}, {1}", obj.x, obj.y); 37 fixed (int* n = &obj.x) 39 { 41 fixed (int* p = &obj.y) 43 { 45 ChangeValue(n, p); //取data地址並傳遞 47 } 49 } 53 Console.WriteLine("改變地址后: {0}, {1}", obj.x, obj.y); 57 Console.ReadLine(); 59 } 61 }