• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C#之不安全代码(2)

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

&fixed将变量分为两类:固定的和活动的。

固定的变量永久的存在并不会被GC的操作影响。(例如局部变量,值参数和间接指针)活动的变量会被GC重新分配位置或是释放(例如对象中的字段,基础数据数组)。

&取固定变量的地址是没有限制的。但是活动变量容易受GC的影响,其地址只能通过fixed来获得,并且地址仅会在整个fixed语句的周期持续有效。

静态字段也是活动变量。还有标记为refout的也是活动变量,即使这个参数是传递给固定参数的。最后,通过间接指针引用的变量总是固定变量。

 

指针转换

在不安全上下文中,下面的转换是隐式的:

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

指针转换并不改变指针的值。也就是说指针转换前后不影响地址的值。

当转换发生后,当结果指针没有按照正确的指针类型排列的话,当访问结果时结果是无法预知的。

下面的例子:

 

1 char c = 'A';
2 char* pc = &c;
3 void* pv = pc;
4 int* pi = (int*)pv;
5 int i = *pi;        // undefined
6 *pi = 123456;        // undefined
7 

 

 

下面的例子会打印出double8字节的值:

 

 1 using System;
 2 class Test
 3 {
 4     unsafe static void Main() {
 5       double d = 123.456e23;
 6         unsafe {
 7            byte* pb = (byte*)&d;
 8             for (int i = 0; i < sizeof(double); ++i)
 9                Console.Write("{0:X2} "*pb++);
10             Console.WriteLine();
11         }
12     }
13 }
14 

 

打印结果取决于endian

 

指针数组

在不安全上下文中,是允许指针数组的,只有几种用于其转换是允许的:

l  从任何数组类型到System.Array或是实现了其接口的隐式引用类型转换同样适用于指针数组。但是,任何试图通过System.Array或是实现了其接口访问数组元素都会引发一个 运行时错误,因为指针类型不能转化为object

l  从一个一维数组类型S[]System.Collections.Generic.IList<T>或是到其基接口,任何显示或是隐式的转换都是不行的。因为指针类型不能被用作类型参数,还有没有从指针类型到非指针类型的转换。

l  System.Array或是实现了其接口到任何数组类型显示引用转换适用于指针数组。

l  System.Collections.Generic.IList<T>或是到其基接口到一个一维数组类型T[],任何显示的转换都是不行的。原因同上面第2条。

还有就是对于foreach语句,不适用于指针数组。相反,下面的语句

foreach (V v in x) embedded-statement

中的x是一个数组类型T[,,…,],n是数组的维度减1TV是指针类型,被改写为:

{
      T[,,…,] a = x;
      V v;
      for (int i0 = a.GetLowerBound(0); i0 <= a.GetUpperBound(0); i0++)
      for (int i1 = a.GetLowerBound(1); i1 <= a.GetUpperBound(1); i1++)
     
      for (int i
n = a.GetLowerBound(n); in <= a.GetUpperBound(n); in++) {
            v
 = (V)a.GetValue(i0,i1,…,in);
                                embedded-statement
      }
}

变量a,i0,i1,…对于x或者embedded-statement或者其余部分的代码是不可见的或是不可访问的。变量vembedded-statement中是只读的。如果没有显示转换从TV,那么就会有错误。如果x是个null,就会有空引用异常。

 

表达式中的指针

在不安全上下文中,一个表达式的值可以来自于一个指针类型;但是在上下文之外,会造成编译时期错误。

间接访问

一元的*表示一个指针,被用来获得指针指向的值。*用在void*类型表达式或是非指针类型表达式时,会造成编译期错误。

*被用在null指针时是由实现来决定的。不能保证在使用时会抛出System.NullReferenceException

如果一个非法的值赋给指针,那么*的行为是不可预知的。

指针成员访问

在指针成员访问P->IP必须是除了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
->= 10;
            p
->= 20;
            Console.WriteLine(p
->ToString());
        }
    }
}
或是:
class Test
{
    
static void Main() {
        Point point;
        
unsafe {
            Point
* p = &point;
            (
*p).x = 10;
            (
*p).y = 20;
            Console.WriteLine((
*p).ToString());
        }
    }
}

 

指针元素访问

在指针元素访问P[E]中,P必须是除了void*之外的类型,同时E必须能隐式的转换为int, uint, long, or ulong的表达式。

P[E]效果上同*(P + E).例如:

 

 1 class Test
 2 {
 3     static void Main() {
 4         unsafe {
 5             char* p = stackalloc char[256];
 6             for (int i = 0; i < 256; i++) p[i] = (char)i;
 7         }
 8     }
 9 }
10 又如:
11 class Test
12 {
13     static void Main() {
14         unsafe {
15             char

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
C#基础—不安全代码(unsafecode)发布时间:2022-07-14
下一篇:
C#HookC#Hook原理及EasyHook简易教程发布时间:2022-07-14
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap