//
//可以在类型或成员的声明中使用 unsafe 修饰符引入不安全上下文以下两种情况:
//表明文本范围内可以在其中使用语言的不安全功能,其中的代码可能是潜在的不安全代码 (例如含有指针的代码),
//也就是在CLR的正常控制之外存在的代码或内存,无法通过公共语言运行库验证不安全代码。
//1.类型声明:整个类型正文范围均被视为不安全上下文,在类中所有地方都可以使用不安全功能(指针)。
//2.类型成员:整个成员正文范围均被视为不安全上下文,在该成员中所有地方都可以使用不安全功能(指针)。
//若要编译包含不安全代码的托管应用程序,必须指定 /unsafe 编译器选项。
//指针类型是一个单独类别的类型。与引用类型和值类型不同,指针类型不从 object 继承,而且不存在指针类型和 object 之间的转换。
//在不安全代码中,可以声明和操作指针,可以在指针和整型之间执行转换,还可以获取变量的地址,确保指针分配安全是开发人员的责任。
//指针类型中,在 * 前面指定的类型称为该指针类型的目标类型。它表示该指针类型的值所指向的变量的类型。指针的目标类型必须为“非托管类型”。
//与引用(引用类型的值)不同,指针不受垃圾回收器跟踪(垃圾回收器不了解指针和它们指向的数据),指针是在GC的控制范围之外的 。
//不允许指针指向引用或者包含引用的结构,并且指针的目标类型必须是非托管类型。
//非托管类型可以是:
//1.sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal 或 bool。
//2.任何“枚举类型”。
//3.任何“指针类型”。
//4.任何由用户定义的只包含“非托管类型”字段的“结构类型”。
//
//将指针和引用进行混合使用时的基本规则是;引用(对象)的目标可以包含指针,但指针的目标不能包含引用。
//在C#中通常用引用来抽象化指针,引用将一个指针抽象为在托管堆上的内存,该引用和相关内存由GC来管理并需要再定位。
//引用是可移动类型,指向托管堆内存的一个可移动位置,无法转换成指针。
//只能在 unsafe 上下文中使用 fixed 语句。
//该语句用于暂时“固定”一个可移动变量,从而使该变量的地址在语句的持续时间内保持不变,以便可以获取它的地址。
//fix语句在一个模块区间固定内存。在这个模块中,内存是不可移动的并且是免于垃圾回收的。
//固定变量:其住留的存储位置不受垃圾回收器操作的影响,例如局部变量、值参数、结构类型的成员等。
//可移动变量:其住留在会受到垃圾回收器的重定位或处理操作的影响的存储位置,例如对象中的域、静态域,数组的元素等。
//&允许不受限制的获取固定变量的地址,而可移动变量会受到垃圾回收器的重定位或处理,
//因此可移动变量的地址只能使用fix语句获得,而且该地址只在fix语句的生命期内有效,
//fix语句确保由该地址引用的变量在fix语句的生命期内不会被垃圾回收器的重定位或处理。
//由 fixed 语句声明的局部变量被视为只读。
//如果嵌入语句试图修改此局部变量(通过赋值或 ++ 和 -- 运算符)或者将它作为 ref 或 out 参数传递,则将出现编译时错误。
//固定对象可能导致中产生存储碎片(因为它们无法移动)。出于该原因,只有在绝对必要时才应当固定对象,而且固定对象的时间越短越好。
//一个基类的不安全状态不会被一个派生类继承,除非被显式声明为不安全,否则一个派生类是安全的。
//unsafe不属于类型定义语句中的成分,所以它不会被派生类继承。
// stackalloc:在堆栈上而不是在堆上分配一个内存块,此内存块的生存期仅限于定义该内存块的方法的生存期。
// 这个内存是固定的,不能用于垃圾回收,它在函数结束的时候自动释放。
// 必须在一个不安全上下为文内使用,仅在局部变量的初始值设定项中有效。
// type * ptr = stackalloc type [ expr ];
// 其中:
// type
// 非托管类型。
// ptr
// 指针名。
// expr
// 整型表达式。
//它的大小足以包含 type 类型的 expr 元素;该块的地址存储在 ptr 指针中。
//此内存不受垃圾回收的制约,因此不必将其钉住(通过 fixed)。
using System;
namespace Unsafe
{
class Class1
{
private static int [] numbers={5,10,15,20,25,30};
public class Starter
{
public static void Main()
{
//unsafe
int number=296;
byte b;
unsafe
{
b=MethodA(&number);
}
Console.WriteLine(b+"\n");
//fixed
unsafe
{
int count=0;
Console.WriteLine("Pointer Value:");
fixed(int *pI=numbers)
{
foreach(int a in numbers)
{
Console.WriteLine("{0} : {1} : {2}",
(int)(pI+count), *(pI+count),a);
++count;
}
}
Console.WriteLine();
}
//stackalloc
unsafe
{
char* pChar=stackalloc char[26];
char* _pChar=pChar;
for(int count=0;count<26;++count)
{
(*_pChar)=(char)(((int)('A'))+count);
++_pChar;
}
for(int count=0;count<26;++count)
{
Console.Write(pChar[count]);
}
Console.WriteLine();
}
}
public unsafe static byte MethodA(int *pI)
{
byte *temp=(byte*) pI;
return *temp;
}
}
}
}