编写非安全代码需要使用特殊的关键字unsafe与fixed。如果你还记得的话,有三种指针操作符:
- *
- &
- ->
任何使用了上述任一指针操作符的语句、语句块或者函数都应用unsafe关键字标记为非安全代码,就象这样:
public unsafe void Triple(int *pInt)
{
*pInt=(*pInt)*3;
}
上面这个函数只是将传入的参数的值扩大了两倍。但是请注意,传入的是这个参数的指针!因为这个函数使用了"*"操作符直接进行内存操作,因此被标记为 unsafe。
但是这里还是有一个问题。回想一下上面的讨论,非安全代码也是在CLR管理下的受控代码,CLR可以自由地将对象移入内存中。于是一个似是而非的原因可能导致内存泄漏。这样做的结果是,对于编程者可能在自觉不自觉中使这个变量的指针指向内存的其他地方。
因此假设*pInt指向的地址是1001,而CLR的内存重定位过程将会引发内存泄漏。pInt之前指向1001,在重定位后其指向的数据可能被存储在
地址2003处。于是大祸临头了!pInt指向的1001处存储的数据在经过重定位过程后无效了。这也许就是.NET很少提及指针的使用的原因吧,你认为
呢?
固定指针
在语句块前输入关键字fixed,将会告诉CLR块内的对象不能重定位,这样CLR就不会重定位指针指向的数据存储位置。因此在C#中使用指针时,使用关键字fixed将能阻止程序运行时无效指针的产生。让我们看看它是如何工作的:
using System;
class CData
{
public int x;
}
class CProgram
{
unsafe static void SetVal(int *pInt)
{
*pInt=1979;
}
public unsafe static void Main()
{
CData d = new CData();
Console.WriteLine("Previous value: {0}", d.x);
fixed(int *p=&d.x)
{
SetVal(p);
}
Console.WriteLine("New value: {0}", d.x);
}
}
我们在这段代码里通过一个fixed块,将CData对象数据成员(域)x的地址赋给了一个整数型指针p。当fixed块中的语句被执行时,这 个指针p将一直指向原来的那块内存区域,因为CLR已被指示暂时冻结这个变量直到该fixed块执行完毕。一旦fixed块执行完毕,这个对象就又能被 CLR重新定位了。
[注]以上内容转自http://zhangjjwm.cnblogs.com/
以下为MSDN上的例子// compile with: /unsafe
using System;
class Point
{
public int x, y;
}
class FixedTest
{
// Unsafe method: takes a pointer to an int.
unsafe static void SquarePtrParam (int* p)
{
*p *= *p;
}
unsafe static void Main()
{
Point pt = new Point();
pt.x = 5;
pt.y = 6;
// Pin pt in place:
fixed (int* p = &pt.x)
{
SquarePtrParam (p);
}
// pt now unpinned
Console.WriteLine ("{0} {1}", pt.x, pt.y);
}
}