以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一个方法体
- class UnsafeTest1
- {
- unsafe static void AddParam(int *a)
- {
- *a = *a 10000;
- } .
- unsafe public static void Main()
- {
- int i = 10000;
- AddParam (&i);
- Console.WriteLine(i);
- }
- }
2.unsafe一段代码
- private void button1_Click(object sender, EventArgs e)
- {
- unsafe
- {
- int *pInt;
- }
- }
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 还可用于创建固定大小的缓冲区。
- using System;
- class CaryData
- {
- public int data;
- }
- class CProgram
- {
- unsafe static void ChangeValue(int* pInt)
- {
- *pInt = 23;
- }
- public unsafe static void Main()
- {
- CaryData cd = new CaryData();
- Console.WriteLine("改变前: {0}", cd.data);
- fixed (int* p = &cd.data)
- {
- ChangeValue(p);
- }
- Console.WriteLine("改变后: {0}", cd.data);
- }
- }
五,参考
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
---------全文完 ------