不安全
unsafe
關鍵字可用於型別或方法宣告或宣告內聯塊。
此關鍵字的目的是為相關塊啟用 C# 的不安全子集。不安全子集包括指標,堆疊分配,類 C 陣列等功能。
不安全的程式碼是不可驗證的,這就是為什麼不鼓勵使用它的原因。編譯不安全程式碼需要將開關傳遞給 C#編譯器。此外,CLR 要求正在執行的程式集具有完全信任。
儘管有這些限制,但不安全的程式碼在使某些操作更高效(例如陣列索引)或更容易(例如與一些非託管庫互操作)方面具有有效的用法。
作為一個非常簡單的例子
// compile with /unsafe
class UnsafeTest
{
unsafe static void SquarePtrParam(int* p)
{
*p *= *p; // the '*' dereferences the pointer.
//Since we passed in "the address of i", this becomes "i *= i"
}
unsafe static void Main()
{
int i = 5;
// Unsafe method: uses address-of operator (&):
SquarePtrParam(&i); // "&i" means "the address of i". The behavior is similar to "ref i"
Console.WriteLine(i); // Output: 25
}
}
在使用指標時,我們可以直接更改記憶體位置的值,而不必通過名稱來解決它們。請注意,這通常需要使用 fixed 關鍵字來防止可能的記憶體損壞,因為垃圾收集器會移動東西(否則,你可能會收到錯誤 CS0212 )。由於無法寫入已經修復的變數,我們通常還必須有一個第二個指標,該指標開始指向與第一個相同的位置。
void Main()
{
int[] intArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
UnsafeSquareArray(intArray);
foreach(int i in intArray)
Console.WriteLine(i);
}
unsafe static void UnsafeSquareArray(int[] pArr)
{
int len = pArr.Length;
//in C or C++, we could say
// int* a = &(pArr[0])
// however, C# requires you to "fix" the variable first
fixed(int* fixedPointer = &(pArr[0]))
{
//Declare a new int pointer because "fixedPointer" cannot be written to.
// "p" points to the same address space, but we can modify it
int* p = fixedPointer;
for (int i = 0; i < len; i++)
{
*p *= *p; //square the value, just like we did in SquarePtrParam, above
p++; //move the pointer to the next memory space.
// NOTE that the pointer will move 4 bytes since "p" is an
// int pointer and an int takes 4 bytes
//the above 2 lines could be written as one, like this:
// "*p *= *p++;"
}
}
}
輸出:
1
4
9
16
25
36
49
64
81
100
unsafe
還允許使用 stackalloc ,它將在 C 執行時庫中像_alloca 一樣在堆疊上分配記憶體。我們可以修改上面的例子來使用 stackalloc
如下:
unsafe void Main()
{
const int len=10;
int* seedArray = stackalloc int[len];
//We can no longer use the initializer "{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}" as before.
// We have at least 2 options to populate the array. The end result of either
// option will be the same (doing both will also be the same here).
//FIRST OPTION:
int* p = seedArray; // we don't want to lose where the array starts, so we
// create a shadow copy of the pointer
for(int i=1; i<=len; i++)
*p++ = i;
//end of first option
//SECOND OPTION:
for(int i=0; i<len; i++)
seedArray[i] = i+1;
//end of second option
UnsafeSquareArray(seedArray, len);
for(int i=0; i< len; i++)
Console.WriteLine(seedArray[i]);
}
//Now that we are dealing directly in pointers, we don't need to mess around with
// "fixed", which dramatically simplifies the code
unsafe static void UnsafeSquareArray(int* p, int len)
{
for (int i = 0; i < len; i++)
*p *= *p++;
}
(輸出與上面相同)