云镜

指缝太宽,时间太瘦!

博客园 首页 新随笔 联系 订阅 管理

以C#为例。

一,打开unsafe编程开关

   工程中默认的配置是不支持代码的非安全性的,所以第一次使用你得:

      解决方案管理器→→Properties→→生成选项卡→→允许不安全代码。

二,何时要用unsafe

1.一个原则

   unsafe 关键字表示不安全上下文,该上下文是任何涉及指针的操作所必需的。

2.什么时候用指针

    msdn里说 “在 C# 中很少需要使用指针,但仍有一些需要使用的情况。例如,在下列情况中使用允许采用指针的不安全上下文是正确的: 处理磁盘上的现有结构, 涉及内部包含指针的结构的高级COM或平台调用方案, 性能关键代码”

  • Dealing with existing structures on disk
  • Advanced COM or Platform Invoke scenarios that involve structures with pointers in them
  • Performance-critical code

 

   总之,一条判断标准:当你使用C/C++能给带给你的利大于弊时都可以使用unsafe编程,呵呵。

三,unsafe的使用方法(几个例子)

1.unsafe一个方法体

  1.  class UnsafeTest1    
  2.  {    
  3.  unsafe static void AddParam(int *a)    
  4.   {    
  5.   *a = *a 10000;    
  6.   } .    
  7.  unsafe public static void Main()    
  8.   {    
  9.  int i = 10000;    
  10.  AddParam (&i);    
  11. Console.WriteLine(i);    
  12.  }    
  13. }   

2.unsafe一段代码

  1. private void button1_Click(object sender, EventArgs e)  
  2. {  
  3.     unsafe  
  4.     {  
  5.         int *pInt;  
  6.     }  
  7. }  

3.网上找的一个较大unsafe例子

   1. using System;  
   2. using System.Collections.Generic;  
   3. using System.Text;  
   4. namespace UnsafeCode  
   5. {  
   6.   #region Unsafe types and members (just for testing purposes)  
   7.   // This entire structure is 'unsafe' and can  
   8.   // be used only in an unsafe context.  
   9.   public unsafe struct Node  
  10.   {  
  11.     public int Value;  
  12.     public Node* Left;  
  13.     public Node* Right;  
  14.   }  
  15.   // This struct is safe, but the Node* members  
  16.   // are not. Technically, you may access 'Value' from  
  17.   // outside an unsafe context, but not 'Left' and 'Right'.  
  18.   public struct Node2  
  19.   {  
  20.     public int Value;  
  21.     // These can be accessed only in an unsafe context!  
  22.     public unsafe Node2* Left;  
  23.     public unsafe Node2* Right;  
  24.   }  
  25.   #endregion  
  26.   #region Simple Point / PointRef  
  27.   struct Point  
  28.   {  
  29.     public int x;  
  30.     public int y;  
  31.     public override string ToString()  
  32.     { return string.Format("({0}, {1})", x, y); }  
  33.   }  
  34.   class PointRef  
  35.   {  
  36.     public int x;  
  37.     public int y;  
  38.     public override string ToString()  
  39.     { return string.Format("({0}, {1})", x, y); }  
  40.   }    
  41.   #endregion  
  42.   class Program  
  43.   {  
  44.     static void Main(string[] args)  
  45.     {  
  46.       Console.WriteLine("***** Fun with Pointers *****");  
  47.       #region Swap 2 ints safely and unsafely  
  48.       // Values for swap.  
  49.       int i = 10, j = 20;  
  50.       // Swap values 'safely'.  
  51.       Console.WriteLine("\n***** Safe swap *****");  
  52.       Console.WriteLine("Values before safe swap: i = {0}, j = {1}", i, j);  
  53.       SafeSwap(ref i, ref j);  
  54.       Console.WriteLine("Values after safe swap: i = {0}, j = {1}", i, j);  
  55.       // Swap values 'unsafely'.  
  56.       Console.WriteLine("\n***** Unsafe swap *****");  
  57.       Console.WriteLine("Values before unsafe swap: i = {0}, j = {1}", i, j);  
  58.       unsafe { UnsafeSwap(&i, &j); }  
  59.       Console.WriteLine("Values after unsafe swap: i = {0}, j = {1}", i, j);  
  60.       Console.WriteLine();  
  61.       #endregion  
  62.       UsePointerToPoint();  
  63.       Console.WriteLine();  
  64.       UseSizeOfOperator();  
  65.       Console.ReadLine();  
  66.     }  
  67.     public static void SafeSwap(ref int i, ref int j)  
  68.     {  
  69.       int temp = i;  
  70.       i = j;  
  71.       j = temp;  
  72.     }  
  73.     #region Various unsafe methods  
  74.     unsafe static void PrintValueAndAddress()  
  75.     {  
  76.       int myInt;  
  77.       // Define an int pointer, and  
  78.       // assign it the address of myInt.  
  79.       int* ptrToMyInt = &myInt;  
  80.       // Assign value of myInt using pointer indirection.  
  81.       *ptrToMyInt = 123;  
  82.       // Print some stats.  
  83.       Console.WriteLine("Value of myInt {0}", myInt);  
  84.       Console.WriteLine("Address of myInt {0:X}", (int)&ptrToMyInt);  
  85.     }  
  86.     unsafe static void SquareIntPointer(int* myIntPointer)  
  87.     {  
  88.       // Work with pointer types here!  
  89.       // Square the value just for a test.  
  90.       *myIntPointer *= *myIntPointer;  
  91.     }  
  92.     unsafe public static void UnsafeSwap(int* i, int* j)  
  93.     {  
  94.       int temp = *i;  
  95.       *i = *j;  
  96.       *j = temp;  
  97.     }  
  98.     unsafe static void UsePointerToPoint()  
  99.     {  
 100.       // Access members via pointer.  
 101.       Point point;  
 102.       Point* p = &point;  
 103.       p->x = 100;  
 104.       p->y = 200;  
 105.       Console.WriteLine(p->ToString());  
 106.       // Access members via pointer indirection.  
 107.       Point point2;  
 108.       Point* p2 = &point2;  
 109.       (*p2).x = 100;  
 110.       (*p2).y = 200;  
 111.       Console.WriteLine((*p2).ToString());  
 112.     }  
 113.     unsafe static void UnsafeStackAlloc()  
 114.     {  
 115.       char* p = stackalloc char[256];  
 116.       for (int k = 0; k < 256; k++)  
 117.         p[k] = (char)k;  
 118.     }  
 119.     unsafe public static void UseAndPinPoint()  
 120.     {  
 121.       PointRef pt = new PointRef();  
 122.       pt.x = 5;  
 123.       pt.y = 6;  
 124.       // pin pt in place so it will not  
 125.       // be moved or GC-ed.  
 126.       fixed (int* p = &pt.x)  
 127.       {  
 128.         // Use int* variable here!  
 129.       }  
 130.       // pt is now unpinned, and ready to be GC-ed.  
 131.       Console.WriteLine("Point is: {0}", pt);  
 132.     }  
 133.     unsafe static void UseSizeOfOperator()  
 134.     {  
 135.       Console.WriteLine("The size of short is {0}.", sizeof(short));  
 136.       Console.WriteLine("The size of int is {0}.", sizeof(int));  
 137.       Console.WriteLine("The size of long is {0}.", sizeof(long));  
 138.       Console.WriteLine("The size of Point is {0}.", sizeof(Point));  
 139.     }  
 140.     #endregion  
 141.   }  
 142. } 

四,使用unsafe时可能用到的fixed

   1.为什么要用fixed

       Unsafe的代码托管代码 (managed code)和非托管代码(Unmanaged Code)之间,它也是在CLR的环境中执行,但是可以用来直接操作内存。但由于代码是在CLR下托管执行,为了减少内存碎片C#的自动垃圾回收机制会允 许已经分配的内存在运行时进行位置调整,所以如果我们多次调用的话就可能 导致指针指向其他的变量。比如*pInt为指向一个变量的地址为1001,CLR在重新内存整理分配后该变量就存储在地址为5001的地方。而原来 1001的地方可能会被分配其他变量,要解决这个问题我们就需要使用Fixed关键字。

   2.使用fixed的例子

     fixed 语句禁止垃圾回收器重定位可移动的变量。fixed 语句只能出现在不安全的上下文中。Fixed 还可用于创建固定大小的缓冲区。

  1. using System;  
  2. class CaryData  
  3. {  
  4.     public int data;  
  5. }  
  6. class CProgram  
  7. {  
  8.      
  9.     unsafe static void ChangeValue(int* pInt)  
  10.     {  
  11.         *pInt = 23;  
  12.     }  
  13.     public unsafe static void Main()  
  14.     {  
  15.         CaryData cd = new CaryData();  
  16.         Console.WriteLine("改变前: {0}", cd.data);          
  17.         fixed (int* p = &cd.data)  
  18.         {  
  19.             ChangeValue(p);  
  20.         }  
  21.         Console.WriteLine("改变后: {0}", cd.data);  
  22.     }  
  23. }  

五,参考

 

1.http://msdn.microsoft.com/zh-cn/library/chfa2zb8.aspx

2.http://msdn.microsoft.com/zh-cn/library/f58wzh21.aspx

3.http://msdn.microsoft.com/en-us/library/t2yzs44b%28v=VS.80%29.aspx

 

---------全文完 ------

posted on 2010-06-08 10:55  Yunjiung  阅读(2308)  评论(2编辑  收藏  举报