c#在默認情況下生成的都是安全代碼,即進行了代碼托管(.NET的CLR機制好處之一是,進行代碼托管,適時的釋放內存,程序員便不必考慮資源的回收問題),而此時,指針不能出現在安全代碼的編譯條件下。
一、unsafe
如果因需要想在c#中使用指針,那么unsafe便是一個通道(當然在使用前,需在項目屬性的生成選項中,選擇“允許不安全代碼”)。
example 1:
a) 創建項目,項目屬性->生成->選擇“允許不安全代碼”
b) 編寫代碼
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace ConsoleDll { //此處為c++動態庫的調用,因 DllC++.dll是示例測試文件,為不影響代碼演示,此處屏蔽 //public class Code //{ // [DllImport("DllC++.dll")] // public unsafe static extern int Add(int a, int* b); //} class Program { public unsafe static int Add(int a, int* b)//此處使用 指針,需要加入非安全代碼關鍵字unsafe { return a + *b; } static void Main(string[] args) { unsafe//此代碼塊為非安全代碼,可以使用指針 { int resDll,resInner, a; int* b;//如果在安全代碼條件下,編譯不會通過對指針的定義 a = 1; b = &a; // resDll = Code.Add(a, b); resInner = Add(a,b); } } } }
上面代碼簡單的示范了何種情況下可以使用指針。
二、fixed
fixed其實是在非安全代碼下用到才會有意義的。因為他負責對指針所指向的“動態分配內存的對象或對象中的成員”簡稱“對象”進行鎖定(之所以要鎖 定,是因為即使在非安全代碼模式下,這些對象一樣的使用CLR的代碼托管,這樣的話,很可能造成對象的地址變動,就是因為CLR對資源重新分配的不確定 性,假使指針在未完成對對象的操作時,對象地址變動,那么指針指向的地址就會出現混亂,很可能造成內存泄漏甚至系統崩潰。如果使用fixed進行鎖定,那 么只有在執行完fixed模塊后,指針所指向的對象才能被移動)。
a) 垃圾回收機制,維護引用信息不維護指針信息
b) 引用類型的實例化對象在生存期內由垃圾回收機制處理,可能移動內存
c) 當一個類的實例化對象中含有值類型時,定義指向這些值類型的指針編譯報error,因為這些內嵌在引用類型中的值類型實例會隨着引用實例化對象的內存移動而移動,所以指針值在不知情的情況下會發生變化,fixed關鍵字做的工作便是讓這樣的類實例化對象(不是類類型本身,而是一個實例化對象)
example 2:
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace ConsoleDll { //例子1
unsafe void SquarePtrParam(int* p)
{
*p *= *p;
}
public unsafe void run()
{
int[] arr = new int[] { 1, 2, 3, 4, 5 };
fixed (int* p = &arr[0]) //此處將鎖住arr[0],使得在fixed操作塊內,arr[0]不會被CLR移動
{
for (int i = 0, n = arr.Length; i < n; i++)
{
SquarePtrParam(p + i);
Console.WriteLine(p[i]);
}
}
}
//例子2
public static int Add(int[] a,int b) { unsafe { fixed (int* pa = a)//此處將鎖住a,使得在fixed操作塊內,a不會被CLR移動 { return *pa + b; } } } static void Main(string[] args) { int[] a = new int[1]; a[0] = 1; int b = 2; int res = Add(a,b); } } }
上述代碼需注意的是:pa的地址也是被固定了的,所以不能對他進行賦值操作。