固定的和活动的变量
&和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;
}
}
}