《《不安全代码》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《不安全代码》PPT课件.ppt(26页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、http:/ 不安全代码不安全代码(时间:1次课,2学时)http:/第第16章章 不安全代码不安全代码 n前面各章节介绍的前面各章节介绍的C#源程序都是在公共语言运行时源程序都是在公共语言运行时CLR的管理下执行的的管理下执行的代码,它们都是受控代码,代码,它们都是受控代码,C#语言不允许在受控代码中使用指针语言不允许在受控代码中使用指针(而指而指针恰恰就是带来不安全的根源针恰恰就是带来不安全的根源),所以,所以C#受控代码又称为安全代码,而受控代码又称为安全代码,而使用指针的代码就称为不安全代码。本章重点介绍如何组成使用指针的代码就称为不安全代码。本章重点介绍如何组成C#源程序的源程序的不
2、安全代码块以及在不安全代码中定义和使用指针的方法。不安全代码块以及在不安全代码中定义和使用指针的方法。n本章教学目的:本章教学目的:n掌握指针和不安全代码的概念掌握指针和不安全代码的概念n掌握指针的使用掌握指针的使用n掌握掌握C#中不安全代码的使用机制和实现方法中不安全代码的使用机制和实现方法http:/第第16章章 不安全代码不安全代码 n16.1 不安全代码不安全代码 n16.2 不安全的代码块不安全的代码块 n16.3 C#程序中的指针程序中的指针 http:/16.1 不安全代码不安全代码n由于受控代码中不允许使用指针,所以它是安全的,这对我们的大多数应用程序都是有益的。但是,在由于受
3、控代码中不允许使用指针,所以它是安全的,这对我们的大多数应用程序都是有益的。但是,在某些情况下我们必须使用指针,例如,调用底层操作系统、访问内存映射驱动器某些情况下我们必须使用指针,例如,调用底层操作系统、访问内存映射驱动器(属于系统级的应用属于系统级的应用)以以及执行对时间有严格要求的算法等。为了能在一定的应用中使用指针,及执行对时间有严格要求的算法等。为了能在一定的应用中使用指针,C#语言引入了不安全代码语言引入了不安全代码(unsafe code)的概念,并提供了创建和使用不安全代码的模式。的概念,并提供了创建和使用不安全代码的模式。n指针是指针是C/C+语言的一个重要概念,也是其重要的
4、特色之一。熟悉语言的一个重要概念,也是其重要的特色之一。熟悉C/C+的人都知道指针就是变量的人都知道指针就是变量的内存地址,所以常把变量的地址称为变量的指针,而把存放地址的变量叫做指针变量。因此,指针有的内存地址,所以常把变量的地址称为变量的指针,而把存放地址的变量叫做指针变量。因此,指针有点像点像C#中的引用,但它们是有区别的:指针可以指向任何内存空间,但引用只能指向某个类的对象。中的引用,但它们是有区别的:指针可以指向任何内存空间,但引用只能指向某个类的对象。正因为指针可以指向任何内存空间,所以有可能会被滥用,这就是为什么创建正因为指针可以指向任何内存空间,所以有可能会被滥用,这就是为什么
5、创建C#的受控代码时,不允的受控代码时,不允许使用指针的原因所在。许使用指针的原因所在。nC#允许创建和使用指针,但对指针的使用限制很多,将创建和使用指针的代码称为不安全代码,而且允许创建和使用指针,但对指针的使用限制很多,将创建和使用指针的代码称为不安全代码,而且这种不安全代码不在这种不安全代码不在CLR的控制下执行,所以又称为非受控代码。在的控制下执行,所以又称为非受控代码。在C#语言中要使用指针,首先必须语言中要使用指针,首先必须组成组成C#不安全代码模块不安全代码模块(使用关键字使用关键字unsafe和和fixed),然后才能在,然后才能在C#不安全代码中定义和使用指针不安全代码中定义
6、和使用指针(和在和在C/C+中使用指针的方法一样中使用指针的方法一样)。n现在我们知道现在我们知道C#语言的源程序有两种运行模式:语言的源程序有两种运行模式:“安全安全”模式和模式和“不安全不安全”模式。在前面各章节中介模式。在前面各章节中介绍的例子都是运行在安全模式下的,这也是绍的例子都是运行在安全模式下的,这也是C#语言默认的运行方式。本章将介绍的是语言默认的运行方式。本章将介绍的是C#不安全运行模不安全运行模式。式。n需要强调的是,需要强调的是,C#语言主要是创建受控代码的,它支持非受控代码的能力只是使它可以用来解决一些语言主要是创建受控代码的,它支持非受控代码的能力只是使它可以用来解决
7、一些特殊的应用问题,而这并不是标准的特殊的应用问题,而这并不是标准的C#程序。程序。http:/16.2 不安全的代码块不安全的代码块 u 16.2.1 指针指针 u 16.2.2 unsafe关键字关键字 u 16.2.3 fixed语句语句 http:/16.2 不安全的代码块不安全的代码块 n如果我们的应用问题需要使用指针,则在使如果我们的应用问题需要使用指针,则在使用用C#语言编程时就需要先定义一个不安全代语言编程时就需要先定义一个不安全代码块,在代码块中才能使用指针。码块,在代码块中才能使用指针。http:/16.2.1 指针指针 n在介绍不安全代码块之前,先简单介绍在介绍不安全代码
8、块之前,先简单介绍(或复习或复习)指指针的概念。针的概念。n1.定义指针变量n指针变量就是存放对象地址的变量。比如,变量指针变量就是存放对象地址的变量。比如,变量x保存了变量保存了变量y的地址,那么就说变量的地址,那么就说变量x是指针变量,是指针变量,或者说或者说x指向指向y。定义指针变量的语句格式为:。定义指针变量的语句格式为:n数据类型数据类型*变量名;变量名;http:/16.2.1 指针指针 n2.给指针变量赋值n上述定义上述定义ip为指针变量,表示为指针变量,表示ip将用来保存某个整型变量的将用来保存某个整型变量的内存地址,这个地址就是该变量在计算机内存中的位置。那内存地址,这个地址
9、就是该变量在计算机内存中的位置。那么如何给指针变量么如何给指针变量ip赋一个地址赋一个地址(又叫指针值又叫指针值)呢?呢?n给指针变量赋值要用给指针变量赋值要用“&”运算符,这是运算符,这是“取地址取地址”运算符。运算符。http:/16.2.2 unsafe关键字关键字 n如果我们想要在如果我们想要在C#语言的源程序中使用指针,语言的源程序中使用指针,则必须在相应的类、结构、接口或代理的定则必须在相应的类、结构、接口或代理的定义中使用义中使用unsafe修饰符,或者在语句中使用修饰符,或者在语句中使用unsafe关键字以指定能使用指针的代码区域关键字以指定能使用指针的代码区域“不安全不安全”
10、代码或代码或“非保护非保护”代码。代码。http:/16.2.2 unsafe关键字关键字n【例【例16.1】使用不安全代码。】使用不安全代码。nusing System;npublic class UnsafeCodennunsafe static void MultiMethod(double*dp)/MultiMethod方法中可以方法中可以n使用指针使用指针nn*dp*=2;/dp为指针变量,用于执行乘法赋值运算为指针变量,用于执行乘法赋值运算nnpublic unsafe static void Main()/Main()方法中可以使用变量的指针方法中可以使用变量的指针nndoubl
11、e x=10;nMultiMethod(&x);nConsole.WriteLine(x);nnn程序运行结果:程序运行结果:n20http:/16.2.2 unsafe关键字关键字n在上例中,使用指针变量作为方法的形参,则在调用方法时传递的是变量的地址在上例中,使用指针变量作为方法的形参,则在调用方法时传递的是变量的地址而不是数值;而如果将方法而不是数值;而如果将方法MultiMethod改为不使用指针变量作为形参,则调改为不使用指针变量作为形参,则调用方法之后变量用方法之后变量x的数值是不会变为的数值是不会变为20的,仍然为的,仍然为10。n在上例中不论是使用指针的主方法,还是利用指针变量
12、进行计算的方法,在上例中不论是使用指针的主方法,还是利用指针变量进行计算的方法,MultiMethod的定义中都使用了的定义中都使用了unsafe修饰符。现在我们把主方法代码改写如修饰符。现在我们把主方法代码改写如下:下:nnpublic static void Main()nndouble x=10;nunsafe MultiMethod(&x);/只把调用方法的语句定义为不安全代码只把调用方法的语句定义为不安全代码nConsole.WriteLine(x);nnhttp:/16.2.3 fixed语句语句 n.NET框架的公共语言运行时框架的公共语言运行时CLR环境提供了环境提供了“自动管
13、理内存自动管理内存”的功能的功能(垃圾回收垃圾回收器器),我们在程序设计中只需定义变量,我们在程序设计中只需定义变量(系统根据此变量自动分配内存系统根据此变量自动分配内存),而无需,而无需关心在程序的功能执行完后,如何来释放被变量占用的内存,关心在程序的功能执行完后,如何来释放被变量占用的内存,CLR环境会不定期环境会不定期地对程序所使用的内存进行管理,自动释放无用变量占用的内存。但是,我们不地对程序所使用的内存进行管理,自动释放无用变量占用的内存。但是,我们不知道这种知道这种“自动内存管理自动内存管理”在程序的执行过程中何时发生,而有时我们不希望被在程序的执行过程中何时发生,而有时我们不希望
14、被某个指针变量引用的变量被这种自动内存管理某个指针变量引用的变量被这种自动内存管理“自动处理自动处理”掉掉(移动或回收移动或回收),这,这时在程序中就需要对这个指针变量使用时在程序中就需要对这个指针变量使用fixed关键字加以声明,目的是通知系统,关键字加以声明,目的是通知系统,该指针变量所指向的变量不能按该指针变量所指向的变量不能按“自动管理内存自动管理内存”的方式处理。的方式处理。nfixed语句主要用来防止系统进行语句主要用来防止系统进行“自动内存管理自动内存管理”时移动或释放被某个指针变时移动或释放被某个指针变量所指向的变量。语句格式如下:量所指向的变量。语句格式如下:nfixed(数
15、据类型数据类型 *指针变量指针变量=&变量变量)nn/使用存储位置固定的对象使用存储位置固定的对象n /代码代码nhttp:/16.2.3 fixed语句语句 n【例【例16.2】使用】使用fixed语句。语句。nusing System;npublic class Pointn public int a,b;nclass FixedCodennunsafe static void SquareMethod(int*ip)/不安全方法不安全方法n *ip*=*ip;npublic static void Main()nnPoint pt=new Point();npt.a=10;npt.b=1
16、2;nunsafe /指定不安全代码,指定不安全代码,fixed只能用在只能用在unsafe声明的范围内声明的范围内nnfixed(int*p=&pt.a)/锁定锁定pt.a的存储位置的存储位置nnSquareMethod(p);/传递指针参数传递指针参数nn/执行完执行完fixed语句块后,解除对语句块后,解除对pt.a存储位置的锁定状态存储位置的锁定状态nnConsole.WriteLine(0,1),pt.a,pt.b);nnn程序运行结果:程序运行结果:n(100,12)http:/16.3 C#程序中的指针程序中的指针 u 16.3.1 用指针访问对象用指针访问对象 u 16.3.2
17、 指针运算指针运算 http:/16.3 C#程序中的指针程序中的指针 n 在上两节中,主要介绍了在在上两节中,主要介绍了在C#语言程序中如何解决使用指语言程序中如何解决使用指针的问题。要想在针的问题。要想在C#中使用指针,必须把含有指针运算等中使用指针,必须把含有指针运算等有关的类、方法等语句块用有关的类、方法等语句块用unsafe和和fixed模块圈定起来,模块圈定起来,使代码成为不安全代码。而有关不安全代码中指针的使用与使代码成为不安全代码。而有关不安全代码中指针的使用与C/C+语言中的基本类似,以下再对指针在语言中的基本类似,以下再对指针在C#中的使用方中的使用方法进行说明和复习法进行
18、说明和复习(对掌握对掌握C/C+的程序员的程序员)。http:/16.3.1 用指针访问对象用指针访问对象 n1.指向数组的指针n 使用指针引用数组元素就如同使用数组的下标引用数组元素使用指针引用数组元素就如同使用数组的下标引用数组元素一样方便。一样方便。http:/16.3.1 用指针访问对象用指针访问对象 n【例【例16.3】指向数组的指针。】指向数组的指针。nusing System;npublic class Testnnpublic static int array1=new int 0,1,2,3,4,5,6,7,8,9,;n/定义一个数组定义一个数组npublic static
19、int,array2=new nint,1,2,3,4,5,6,7,8,9,10,11,12;npublic unsafe static void Main()/使用不安全代码使用不安全代码nnfixed(int*py=&array12)/使指针使指针py指向一维数组的某个元素指向一维数组的某个元素(使用取地址使用取地址n运算符运算符&)nnint*p=py;nfor(int i=0;i2;i+)/使用指针来访问部分数组元素使用指针来访问部分数组元素nnp+;/递增地址递增地址n*p+=10;nnforeach(int i in array1)/输出数组元素的值输出数组元素的值nnConsol
20、e.Write(0,5:d ,i);nhttp:/16.3.1 用指针访问对象用指针访问对象 nConsole.WriteLine();nnConsole.WriteLine();nfixed(int*py=&array22,1)/使指针使指针py指向二维数组的某个元素指向二维数组的某个元素nnint*p=py;nfor(int i=0;i运算符来访问结构成员,例如,运算符来访问结构成员,例如,p是一个指向结构对象是一个指向结构对象s的指针变量,的指针变量,m是结构对象是结构对象s的成员,则用指针的成员,则用指针p访问访问m的格的格式为:式为:p-m,这相当于,这相当于s.m。http:/16
21、.3.1 用指针访问对象用指针访问对象 n【例【例16.4】使用结构体对象指针。】使用结构体对象指针。nusing System;npublic struct Point /表示平面中的点表示平面中的点nnpublic int x,y;npublic Point(int x,int y)/构造函数构造函数nnthis.x=x;nthis.y=y;nnnpublic struct Rectangle /描述矩形的结构描述矩形的结构nnpublic Point p1;npublic Point p2;npublic Rectangle(Point p1,Point p2)/构造函数构造函数nnth
22、is.p1.x=p1.x;nthis.p1.y=p1.y;nthis.p2.x=p2.x;nthis.p2.y=p2.y;nhttp:/16.3.1 用指针访问对象用指针访问对象 npublic int Area()/求矩形面积的方法求矩形面积的方法nnreturn(p2.x-p1.x)*(p2.y-p1.y);nnnpublic class Appnnpublic unsafe static void Main()nn/创建点对象创建点对象nPoint p1=new Point(1,1);nPoint p2=new Point(10,10);n/创建矩形对象创建矩形对象nRectangle
23、r1=new Rectangle(p1,p2);nConsole.WriteLine(r1.Area();nRectangle*r=&r1;/创建指向结构对象的指针创建指向结构对象的指针n/引用结构成员引用结构成员nr-p2.x=100;nr-p2.y=100;nConsole.WriteLine(r-Area();/使用指针来访问结构的成员要使用运算符使用指针来访问结构的成员要使用运算符“-”,而不是,而不是“.”nnn程序运行结果为:程序运行结果为:n81n9801http:/16.3.2 指针运算指针运算 n1.指针的算术运算n可以在指针上使用可以在指针上使用+、-、+和和-运算来递增和
24、递减指针的运算来递增和递减指针的值,这也就是改变地址值;还可以使用值,这也就是改变地址值;还可以使用=、!、!=、=等比较运算符,对两个指针的值等比较运算符,对两个指针的值(地址地址)进行比较,进行比较,例如,设例如,设p1、p2为指针变量:为指针变量:nif(p1!=p2)nif(p1p2)http:/16.3.2 指针运算指针运算 n2.sizeof运算符nsizeof运算符只能在不安全代码中使用,其用法与运算符只能在不安全代码中使用,其用法与C/C+中一样。使用这个运中一样。使用这个运算符可以获得某种数据类型在内存中所占用的字节数。使用格式为:算符可以获得某种数据类型在内存中所占用的字节
25、数。使用格式为:nsizeof(数据类型数据类型)n其中:数据类型包括各种数值类型、结构和枚举等,不包括引用类型。其中:数据类型包括各种数值类型、结构和枚举等,不包括引用类型。nsizeof运算后的返回值为一个整数值,它表示运算后的返回值为一个整数值,它表示“数据类型数据类型”所占用的字节数。所占用的字节数。n例如:例如:nsizeof(int)=4 nsizeof(double)=8n 要注意的是,在要注意的是,在C/C+语言中,语言中,sizeof运算符可以获得各种数据类型的变量、运算符可以获得各种数据类型的变量、数组等占据内存的字节数。但在数组等占据内存的字节数。但在C#语言中,语言中,
26、sizeof运算符只能对数值类型的变运算符只能对数值类型的变量进行运算,而量进行运算,而sizeof(string)在在C#中就是非法的。中就是非法的。http:/16.3.2 指针运算指针运算 n3.stackalloc运算符n在在C#的不安全代码中,还可以使用的不安全代码中,还可以使用stackalloc运算符在栈中为变量分配内存,其作用类运算符在栈中为变量分配内存,其作用类似于似于new运算符。运算符。nstackalloc运算符的使用格式为:运算符的使用格式为:n数据类型数据类型*指针变量指针变量=stackalloc 数据类型数据类型表达式表达式n其中:其中:l数据类型包括各种数值类
27、型、结构和枚举等,不包括引用类型。数据类型包括各种数值类型、结构和枚举等,不包括引用类型。l指针变量是指针变量是C#合法的标识符。合法的标识符。lstackalloc运算符后的数据类型必须与前面的数据类型一致。运算符后的数据类型必须与前面的数据类型一致。l 内的表达式是一个通过运算可以获得整数类型数据的表达式,表达式的计算结果表示待内的表达式是一个通过运算可以获得整数类型数据的表达式,表达式的计算结果表示待分配内存的元素个数。分配内存的元素个数。n例如:例如:char*ct=stackalloc char10;n这条语句表示在栈中将分配一个存储这条语句表示在栈中将分配一个存储10个字符的内存空间,并将该内存空间的首地址赋给个字符的内存空间,并将该内存空间的首地址赋给指针变量指针变量ct。n需要说明的是,用户无法显式地释放使用需要说明的是,用户无法显式地释放使用stackalloc运算符分配的内存,这些内存会在方运算符分配的内存,这些内存会在方法返回后被自动释放。如果使用法返回后被自动释放。如果使用stackalloc运算符分配内存时没有足够的内存,则系统会运算符分配内存时没有足够的内存,则系统会抛出一个抛出一个System.StackOverflowException异常。异常。http:/Q&A?Thanks!
限制150内