C#指针- 常用手段

来源:互联网 发布:灯光编程教学视频 编辑:程序博客网 时间:2024/05/01 11:24

C#指针- 常用手段

分类: C# 340人阅读 评论(0) 收藏 举报

  指针真是一把神器啊!使用C#加指针来搞一下图像去色效果,整个过程低于15毫秒。而在不加指针的情况下却需要500毫秒。如果用C语言+指针来搞那就更快了。难怪操作系统用C#写不了。国庆这几天,除了和爸爸聊聊天,看看电影。没事就百度,谷歌,博客园搜一些C#指针的文章来看,但能找到的资料很少。

  我看了好几篇C#指针的文章后,遇到一个问题,C#和JAVA一样请了一个保姆,C#这个保姆比JAVA还能干,在C#几乎全部类都是托管的,而指针只能操作非托管的类,所以C#里的那些操作数据库的类,那些网络编程的类,那些文件处理的类,指针统统不能用。那该怎么办好呢?我百度了N次,找有没有办法把托管的类转换成非托管的,答案是NO!~~~。泪奔啊。有哪位大侠,看到这篇文章,留个言,能说一下解救之法?

  虽然这个问题我没找到解决,但不影响指针此刻在我心中肃立起的高大形象,我觉的它就是玄话武侠小说《诛仙》最强大的武器----诛仙剑。

  来看一下C#操作指针的一些常用手段

  C#要使用指针必需先把这个勾打上。

  常用代码我就直接COPY别人的了, 常用C#+指针原代码的出处是这篇文章《C# 指针复习示例

[csharp] view plaincopy
  1. /// <summary>  
  2.     /// 指针,存储的是一个地址的整数。  
  3.     /// </summary>  
  4.     class Program  
  5.     {  
  6.         delegate void Methods();  
  7.   
  8.         static void Main(string[] args)  
  9.         {  
  10.             Demo6();  
  11.             Console.ReadKey();  
  12.         }  
  13.   
  14.         static void S(object o)  
  15.         {  
  16.             Console.WriteLine(o.ToString());  
  17.         }  
  18.   
  19.         static void S(params object[] o)  
  20.         {  
  21.             foreach (object obj in o)  
  22.                 S(obj);  
  23.         }  
  24.  
  25.         #region 指针简单示例  
  26.         unsafe static void Demo1()  
  27.         {  
  28.             int x = 10;//整数类型  
  29.             int* pX, pY;//指针坐标X、Y  
  30.             pX = &x;//取pX地址  
  31.             pY = pX;//将pX赋值给pY  
  32.   
  33.             x = 15;  
  34.             *pX = 16;  
  35.             *pY = 17;  
  36.   
  37.             S(x);  
  38.             S(*pX);//取得地址的内容  
  39.             S(*pY);  
  40.         }  
  41.         #endregion  
  42.  
  43.         #region 指针的类型转换  
  44.         unsafe static void Demo2()  
  45.         {  
  46.             //NOTE:类型转换后,uint获得的是地址的十进制格式,并非获取地址的内容。  
  47.   
  48.             int x = 10;//整数类型  
  49.             int* pX, pY;//指针坐标X、Y  
  50.             pX = &x;//取pX地址  
  51.             pY = pX;//将pX的地址赋值给pY  
  52.             uint ux = (uint)pX;//类型转换,获取地址的十进制  
  53.             int* pZ = (int*)ux;//类型转换,将地址赋值给pZ  
  54.   
  55.             S(x);  
  56.             S(((uint)pX).ToString("x"));//十六进制内存地址  
  57.             S((uint)pY);//十进制内存地址  
  58.             S(ux);  
  59.             S((uint)pZ);//十进制内存地址  
  60.             S(*pZ);//输出地址的内容  
  61.         }  
  62.         #endregion  
  63.  
  64.         #region DWORD内存块  
  65.         unsafe static void Demo3()  
  66.         {  
  67.             decimal m2 = 4.00m;  
  68.             byte b = 100;  
  69.             short s = 200;  
  70.             int i = 300;  
  71.             long l = 400;  
  72.   
  73.             float f = 1.00f;  
  74.             double d = 2.00;  
  75.             decimal m = 3.00m;  
  76.   
  77.               
  78.             S(string.Format("byte:{0}"sizeof(byte)));  
  79.             S(string.Format("short:{0}"sizeof(short)));  
  80.             S(string.Format("int:{0}"sizeof(int)));  
  81.             S(string.Format("long:{0}"sizeof(long)));  
  82.             S(string.Format("float:{0}"sizeof(float)));  
  83.             S(string.Format("double:{0}"sizeof(double)));  
  84.             S(string.Format("decimal:{0}"sizeof(decimal)));  
  85.             S("");  
  86.             S("从高到矮……");  
  87.             S(string.Format("decimal:{0} +16  ↑", (uint)&m2));  
  88.             S(string.Format("byte:{0} +1  ↑", (uint)&b));  
  89.             S(string.Format("short:{0}  +2  ↑", (uint)&s));  
  90.             S(string.Format("int:{0}  +4  ↑", (uint)&i));  
  91.             S(string.Format("long:{0}  +8  ↑", (uint)&l));  
  92.             S(string.Format("float:{0}  +4  ↑", (uint)&f));  
  93.             S(string.Format("double:{0}  +8  ↑", (uint)&d));  
  94.             S(string.Format("decimal:{0}  +16  ↑", (uint)&m));  
  95.             S("有没有发现byte和short也是4个字节的内存块?因为.NET约定,最少要占用4个字节。");  
  96.         }  
  97.         #endregion  
  98.  
  99.         #region 指针的运算  
  100.         unsafe static void Demo4()  
  101.         {  
  102.   
  103.             byte b = 8;  
  104.             uint u = 3;  
  105.             double d = 10.0;  
  106.   
  107.             byte* pByte = &b;  
  108.             uint* pUint = &u;  
  109.             double* pDouble = &d;  
  110.             S(string.Format("byte:{0}", (uint)pByte));  
  111.             S(string.Format("uint:{0}", (uint)pUint));  
  112.             S(string.Format("double:{0}", (uint)pDouble));  
  113.             pByte -= 3;  
  114.             ++pUint;  
  115.             S("\n");  
  116.             double* pDouble2 = pDouble + 4;  
  117.             S(string.Format("byte:{0}。old - 3 * 1", (uint)pByte));  
  118.             S(string.Format("uint:{0}。old + 4 * 1", (uint)pUint));  
  119.             S(string.Format("double2:{0}。pDouble + 4 * 8", (uint)pDouble2));  
  120.   
  121.         }  
  122.         #endregion  
  123.  
  124.         #region 结构指针  
  125.         unsafe static void Demo5()  
  126.         {  
  127.               
  128.             MyStruct ms = new MyStruct();  
  129.             MyStruct* pms = &ms;  
  130.             (*pms).X = 5;//传统方式  
  131.             pms->Y = 10;//与C++雷同方式  
  132.   
  133.             S(ms.X);  
  134.             S(ms.Y);  
  135.   
  136.             int* X = &(pms->X);  
  137.             S(*X);  
  138.             *X = 15;  
  139.             S(*X);  
  140.             S(ms.X);  
  141.         }  
  142.   
  143.         struct MyStruct  
  144.         {  
  145.             public int X;  
  146.             public int Y;  
  147.         }  
  148.         #endregion  
  149.  
  150.         #region 类指针  
  151.         unsafe static void Demo6()  
  152.         {  
  153.             MyClass mc = new MyClass();  
  154.             //MyClass* pmc = &mc;//error,无法获取托管类型,因为它们嵌入一个对象。(结构是值类型)  
  155.             fixed (int* X = &(mc.X))  
  156.             fixed (int* Y = &(mc.Y))//*X和*Y固定或者fixed (int* X = &(mc.X), Q = &(mc.Y))。唯一限制,数据类型必须都是int*。  
  157.             {  
  158.                 *X = 5;  
  159.                 *Y = 6;  
  160.                 S(mc.X + "<-X  Y-> " + mc.Y);  
  161.                 fixed (int* Z = &(mc.Z))//*Z固定在X中。生命周期在于X、Y之间。  
  162.                 {  
  163.                     *Z = 7;  
  164.                     *X = 8;  
  165.                     *Y = 9;  
  166.                     S(mc.X + "<-X  Y-> " + mc.Y + "  Z->" + mc.Z);  
  167.                 }  
  168.                 *X = 10;  
  169.                 *Y = 11;  
  170.                 S(mc.X + "<-X  Y-> " + mc.Y);  
  171.             }  
  172.   
  173.         }  
  174.         class MyClass  
  175.         {  
  176.             public int X;  
  177.             public int Y;  
  178.             public int Z;  
  179.         }  
  180.         #endregion  

   另外,C#提供一个的关键字stackalloc用于申请堆栈内存。当函数执行完毕后,内存会被自动回收。使用这个堆内存的时候不必担心内存泄漏问题。

[csharp] view plaincopy
  1. public class Program  
  2.  {  
  3.      static unsafe void Main(string[] args)  
  4.      {  
  5.          //分配p1一个100的大小  
  6.          int* p = stackalloc int[100];  
  7.          //赋值操作  
  8.          for (int i = 0; i < 100; i++)  
  9.          {  
  10.              p[i] = i;  
  11.          }  
  12.          //测试内容  
  13.          for (int i = 0; i < 100; i++)  
  14.          {  
  15.              Console.WriteLine(*(p + i));  
  16.          }  
  17.          Console.ReadLine();  
  18.   
  19.      }  
  20.  }  

  最后有一篇《C# 指针之美》的文章,下面这些话摘抄自那里

  指针也可以操作非托管堆上的内存,如:

IntPtr handle = System.Runtime.InteropServices.Marshal.AllocHGlobal(4);             Int32* p = (Int32*)handle;             *p = 20;             MessageBox.Show(p->ToString());             System.Runtime.InteropServices.Marshal.FreeHGlobal(handle);

  System.Runtime.InteropServices.Marshal.AllocHGlobal 用来从非托管堆上分配内存。System.Runtime.InteropServices.Marshal.FreeHGlobal(handle)用来释放从非托管对上分配的内存。这样我们就可以避开GC,自己管理内存了。

  如果使用非托管内存,建议用Dispose模式来管理内存,这样做有以下好处: 可以手动dispose来释放内存;可以使用using 关键字开管理内存;即使不释放,当Dispose对象被GC回收时,也会收回内存。

     下面是Dispose模式的简单例子:

[csharp] view plaincopy
  1. public unsafe class UnmanagedMemory : IDisposable  
  2. {  
  3.     public int Count { getprivate set; }  
  4.   
  5.     private byte* Handle;  
  6.     private bool _disposed = false;  
  7.   
  8.     public UnmanagedMemory(int bytes)  
  9.     {  
  10.         Handle = (byte*) System.Runtime.InteropServices.Marshal.AllocHGlobal(bytes);  
  11.         Count = bytes;  
  12.     }  
  13.   
  14.     public void Dispose()  
  15.     {  
  16.         Dispose(true);  
  17.         GC.SuppressFinalize(true);  
  18.     }  
  19.   
  20.     protected virtual void Dispose( bool isDisposing )  
  21.     {  
  22.         if (_disposed) return;  
  23.         if (isDisposing)  
  24.         {  
  25.             if (Handle != null)  
  26.             {  
  27.                 System.Runtime.InteropServices.Marshal.FreeHGlobal((IntPtr)Handle);  
  28.             }  
  29.         }  
  30.         _disposed = true;  
  31.     }  
  32.   
  33.     ~UnmanagedMemory()  
  34.    {  
  35.       Dispose( false );  
  36.    }  
  37. }  


 使用代码

       using (UnmanagedMemory memory = new UnmanagedMemory(10))            {                int* p = (int*)memory.Handle;                *p = 20;                MessageBox.Show(p->ToString());            }

 

原创粉丝点击