固定的和活動的變量
&和fixed將變量分為兩類固定的和活動的
固定的變量永久的存在並不會被GC的操作影響(例如局部變量值參數和間接指針)活動的變量會被GC重新分配位置或是釋放(例如對象中的字段基礎數據數組)
&取固定變量的地址是沒有限制的但是活動變量容易受GC的影響其地址只能通過fixed來獲得並且地址僅會在整個fixed語句的周期持續有效
靜態字段也是活動變量還有標記為ref或out的也是活動變量即使這個參數是傳遞給固定參數的最後通過間接指針引用的變量總是固定變量
指針轉換
在不安全上下文中下面的轉換是隱式的
l 從任何指針類型到void*
l 從null到任何指針類型
除此之外下面的轉換都是顯式的
l 從任何指針類型到另外的指針類型
l 從sbyte byte short ushort int uint long or ulong到其他類型
l 從任何類型到sbyte byte short ushort int uint long or ulong
指針轉換並不改變指針的值也就是說指針轉換前後不影響地址的值
當轉換發生後當結果指針沒有按照正確的指針類型排列的話當訪問結果時結果是無法預知的
下面的例子
char c = A;
char* pc = &c;
void* pv = pc;
int* pi = (int*)pv;
int i = *pi; // undefined
*pi = ; // undefined
下面的例子會打印出double的字節的值
using System;
class Test
{
unsafe static void Main() {
double d = e;
unsafe {
byte* pb = (byte*)&d;
for (int i = ; i < sizeof(double); ++i)
ConsoleWrite({:X} *pb++);
ConsoleWriteLine();
}
}
}
打印結果取決於endian
指針數組
在不安全上下文中是允許指針數組的只有幾種用於其轉換是允許的
l 從任何數組類型到SystemArray或是實現了其接口的隱式引用類型轉換同樣適用於指針數組但是任何試圖通過SystemArray或是實現了其接口訪問數組元素都會引發一個 運行時錯誤因為指針類型不能轉化為object
l 從一個一維數組類型S[]到SystemCollectionsGenericIList<T>或是到其基接口任何顯示或是隱式的轉換都是不行的因為指針類型不能被用作類型參數還有沒有從指針類型到非指針類型的轉換
l 從SystemArray或是實現了其接口到任何數組類型顯示引用轉換適用於指針數組
l 從SystemCollectionsGenericIList<T>或是到其基接口到一個一維數組類型T[]任何顯示的轉換都是不行的原因同上面第條
還有就是對於foreach語句不適用於指針數組相反下面的語句
foreach (V v in x) embeddedstatement
中的x是一個數組類型T[…]n是數組的維度減T和V是指針類型被改寫為
{
T[…] a = x;
V v;
for (int i = aGetLowerBound(); i <= aGetUpperBound(); i++)
for (int i = aGetLowerBound(); i <= aGetUpperBound(); i++)
…
for (int in = aGetLowerBound(n); in <= aGetUpperBound(n); in++) {
v = (V)aGetValue(ii…in);
embeddedstatement
}
}
變量aii…對於x或者embeddedstatement或者其余部分的代碼是不可見的或是不可訪問的變量v在embeddedstatement中是只讀的如果沒有顯示轉換從T到V那麼就會有錯誤如果x是個null就會有空引用異常
表達式中的指針
在不安全上下文中一個表達式的值可以來自於一個指針類型但是在上下文之外會造成編譯時期錯誤
間接訪問
一元的*表示一個指針被用來獲得指針指向的值*用在void*類型表達式或是非指針類型表達式時會造成編譯期錯誤
*被用在null指針時是由實現來決定的不能保證在使用時會拋出SystemNullReferenceException
如果一個非法的值賦給指針那麼*的行為是不可預知的
指針成員訪問
在指針成員訪問P>I中P必須是除了void*之外的類型I同時必須是一個可訪問的成員
P>I效果上相同於(*P)I例如
using System;
struct Point
{
public int x;
public int y;
public override string ToString() {
return ( + x + + y + );
}
}
class Test
{
static void Main() {
Point point;
unsafe {
Point* p = &point;
p>x = ;
p>y = ;
ConsoleWriteLine(p>ToString());
}
}
}
或是
class Test
{
static void Main() {
Point point;
unsafe {
Point* p = &point;
(*p)x = ;
(*p)y = ;
ConsoleWriteLine((*p)ToString());
}
}
}
指針元素訪問
在指針元素訪問P[E]中P必須是除了void*之外的類型同時E必須能隱式的轉換為int uint long or ulong的表達式
P[E]效果上同*(P + E)例如
class Test
{
static void Main() {
unsafe {
char* p = stackalloc char[];
for (int i = ; i < ; i++) p[i] = (char)i;
}
}
}
又如
class Test
{
static void Main() {
unsafe {
char* p = stackalloc char[];
for (int i = ; i < ; i++) *(p + i) = (char)i;
}
}
}
From:http://tw.wingwit.com/Article/program/net/201311/12670.html