了解.NET的人都知道其定义了两种数据类型:值类型和引用类型。实际上还有第三种:指针类型。要使用指针类型,系统为我们提供了特定的操作符和关键字,可以绕开CLR的内存管理机制,自己处理。
*
|
该操作符用于创建一个指针变量(也就是一个表示直接内存位置的变量)。和在C/C++中一样,同样的操作符用于指针间接寻址
|
&
|
获取内存中变量的地址
|
->
|
访问一个由指针表示的类型的字段(C#的不安全版本)
|
[ ]
|
在不安全的上下文中[ ]索引指针变量指向的位置
|
++, --
|
不安全上下文中,可递增递减
|
+,-
|
加减运算符
|
==,!=,<,>,<=,=>
|
比较和相等
|
stackallo
|
直接在栈上分配C#数组
|
fiexd
|
临时固定一个变量以使他的地址可以被找到
|
1要绕过CLR管理直接操作指针以优化应用程序的特定部分
2要调用基于C的.dll或调用需要指针作为参数的COM服务器。即使在这种情况下,为了支持System.IntPr类型和System.Runtime.InteropServices.Marshal类型,也可以不使用指针。
编写非安全代码时,需要将项目属性中生的的允许不安全代码打勾
代码里需添加unsafe关键字
static void Main(string[] args)
{
unsafe
{
//在此处理指针类型
}
//在此处不可以处理指针类型
}
除了声明代码块为不安全代码外,还可构建“不安全的”结构,类,类型和成员参数。
unsafe struct Node
{
//整个结构都是不安全的
public int Value;
public Node* Left;
public Node* Right;
}
unsafe struct Node2
{
//结构安全,但Node2成员不安全
public int Value;
public unsafe Node2* Left;
public unsafe Node2* Right;
}
静态方法或实例方法都可以被标记为不安全。如果不想强制调用者将调用封装进不安全上下文,可以利用unsafe关键字修改Main().
unsafe static void Main(string[] args)
{
int myInt2 = 5;
zhizhen(&myInt2);
Console.WriteLine(myInt2);
Console.ReadKey();
}
unsafe static void zhizhen(int* myIntPointer)
{
*myIntPointer *= *myIntPointer;
}
建立了不安全上下文后,可以使用*操作符构建数据类型的指针,使用&操作符获取被指向的内存的地址。
声明指针变量
stackallo关键字
在不安全上下文中,可能需要声明一个直接从调用栈分配内存(不受制于.NET垃圾收集器)的本地变量。C#提供了与C运行函数库_alloca等效的stackalloc关键字来满足这个需求.
unsafe static void UnsafeStackalloc()
{
char* p = stackalloc char[256];
for (int k = 0; k < 256; k++)
p[k] = (char)k;
}
使用fixed关键字固定类型
为了将不安全上下内存中的引用类型变量固定,C#提供了fixed关键字。fixed语句设置向托管类型的的指针并在代码执行过程中固定该变量。由于垃圾收集器将在不可预知的情况下重置变量,没有fixed的话。托管变量的指针将没有多大用处。
unsafe static void UseAndPinPoint()
{
PointRef pt = new PointRef();
pt.x = 5;
pt.y = 6;
//在适当的位置固定变量
fixed (int* p = &pt.x)
{
//在此使用int变量
}
Console .WriteLine ("{0}",pt);
}
class PointRef
{
public int x;
public int y;
public override string ToString()
{
return string.Format("({0},{1})", x, y);
}
}
sizeof关键字
sizeof用来获取值类型的字节大小。
unsafe static void UnseofSizeod()
{
Console.WriteLine ("{0}",sizeof (short ));
}