主要參考的是C# Language Specification Version 3.0。
引子
C#是.Net平台上主流的開發語言,和經典的C/C++不同的是,C#所編寫的代碼是托管代碼,由GC來管理內存,省去了new/delete的煩惱。但是,由於某些特殊的要求,比如和底層的操作系統接口,訪問內存映射設備或者實現對時間要求苛刻的算法時,C#提供了不安全代碼。
不安全上下文
不安全代碼只能寫在不安全上下文中。
通過unsafe 修飾符可以修飾:
class, struct, interface, or delegate
field, method, property, event, indexer, operator, instance constructor, destructor, or static constructor
unsafe-statement-block
指針的類型
在不安全上下文中,指針類型和引用類型或是值類型一樣。但是,指針類型可以用在不安全上下文之外的typeof中,雖然這麼做不安全。
Type t = typeof(Int32*);返回的是System.Int32*
指針類型是用非托管類型或是void加上*來表示的。
pointer-type:
unmanaged-type *
void *
unmanaged-type:
type
在*前面的指針類型被稱為指針類型的引用類型。它表明了指針變量的值指向的變量的類型。
非托管類型不是引用類型,也不包含任何嵌套的引用類型的成員。
非托管類型就是下面的一種:
·sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.
·Any enum-type.
·Any pointer-type.
·Any user-defined struct-type that contains fields of unmanaged-types only.
例子:
Example Description byte* Pointer to byte char* Pointer to char int** Pointer to pointer to int int*[] Single-dimensional array of pointers to int void* Pointer to unknown type
和C/C++不同的是,聲明多個指針變量需要:
int *p1,*p2;
但是在C#中,int* p1,p2就聲明了兩個指針變量,並且*是在類型之後,不是在變量名之前。
和引用類型相同的是,指針可以為null(所有位為0),如果訪問一個指向null的指針會引發不可預知的結果。
Void* 表示一個指針指向未知類型。因為指向未知類型,所以不能通過*來訪為指向的變量,也不能對指針進行數學運算。但是,void*可以轉換為任何指針類型,反之亦然。
指針類型是一個單獨的類型。指針類型不是繼承自System.Object,,並且兩者也不能互相轉換。同樣裝箱和拆箱也不適合指針類型。但是不同類型指針之間可以互相轉換。
指針類型不能用於類型參數,當泛型方法的類型參數為指針類型會調用失敗。
指針類型還可用於易變字段類型。
雖然指針還能通過ref和out來傳遞,但是會造成不可預知的行為,當指針指向一個已經不存在的本地變量,或是指向一個實際不再固定的固定對象。比如:
using System;
class Test
{
static int value = 20;
unsafe static void F(out int* pi1, ref int* pi2) {
int i = 10;
pi1 = &i;
fixed (int* pj = &value) {
// ...
pi2 = pj;
}
}
static void Main() {
int i = 10;
unsafe {
int* px1;
int* px2 = &i;
F(out px1, ref px2);
Console.WriteLine("*px1 = {0}, *px2 = {1}",
*px1, *px2); // undefined behavior
}
}
}
方法可以返回指針類型。
unsafe static int* Find(int* pi, int size, int value) {
for (int i = 0; i < size; ++i) {
if (*pi == value)
return pi;
++pi;
}
return null;
}
主要有幾個操作符:
·*被用作間接訪問
·->被用作通過指針來訪為結構的成員
·[]用來做指針的索引器
·&用來獲得變量的地址
·++和—用來自增和自減指針
·+和-用來做指針的算術運算
·==, !=, <, >, <=, and =>用來比較指針
·stackalloc可以從棧上分配內存
·fixed用來臨時固定一個變量,所以它的地址總是可以得到的。