C# 不安全代码完全指南:指针操作与内存管理
指针基础
C# 允许在由 unsafe 修饰符标记的函数或代码块中使用指针变量。不安全代码或非托管代码是使用指针变量的代码块。
指针声明
指针是其值为另一个变量地址的变量,即内存位置的直接地址。与任何变量或常量一样,必须先声明指针才能用它存储变量地址。
指针声明的一般形式:
type *var-name;
有效的指针声明示例:
int *ip; /* 指向整数的指针 */ double *dp; /* 指向双精度浮点数的指针 */ float *fp; /* 指向单精度浮点数的指针 */ char *ch; /* 指向字符的指针 */
使用 unsafe 修饰符的指针示例
using System;
namespace UnsafeCodeApplication {
class Program {
static unsafe void Main(string[] args) {
int var = 20;
int* p = &var;
Console.WriteLine("Data is: {0} ", var);
Console.WriteLine("Address is: {0}", (int)p);
Console.ReadKey();
}
}
}
编译执行上述代码,输出结果类似:
Data is: 20 Address is: 99215364
除了将整个方法标记为 unsafe,也可以只将部分代码标记为 unsafe。下节示例演示了这一点。
通过指针检索数据值
可以使用 ToString() 方法检索指针变量引用位置存储的数据。以下示例演示了这一点:
using System;
namespace UnsafeCodeApplication {
class Program {
public static void Main() {
unsafe {
int var = 20;
int* p = &var;
Console.WriteLine("Data is: {0} ", var);
Console.WriteLine("Data is: {0} ", p->ToString());
Console.WriteLine("Address is: {0} ", (int)p);
}
Console.ReadKey();
}
}
}
编译执行上述代码,输出结果类似:
Data is: 20 Data is: 20 Address is: 77128984
将指针作为参数传递给方法
可以将指针变量作为参数传递给方法。以下示例演示了这一点:
using System;
namespace UnsafeCodeApplication {
class TestPointer {
public unsafe void swap(int* p, int* q) {
int temp = *p;
*p = *q;
*q = temp;
}
public unsafe static void Main() {
TestPointer p = new TestPointer();
int var1 = 10;
int var2 = 20;
int* x = &var1;
int* y = &var2;
Console.WriteLine("Before Swap: var1:{0}, var2: {1}", var1, var2);
p.swap(x, y);
Console.WriteLine("After Swap: var1:{0}, var2: {1}", var1, var2);
Console.ReadKey();
}
}
}
编译执行上述代码,输出结果如下:
Before Swap: var1: 10, var2: 20 After Swap: var1: 20, var2: 10
使用指针访问数组元素
在 C# 中,数组名和指向数组数据相同类型的指针不是同一变量类型。例如,int *p 和 int[] p 不是同一类型。指针变量 p 可以递增,因为它在内存中不固定;但数组地址在内存中是固定的,不能递增。
因此,若需像 C/C++ 传统方式那样使用指针访问数组数据,需使用 fixed 关键字固定指针。
以下示例演示了这一点:
using System;
namespace UnsafeCodeApplication {
class TestPointer {
public unsafe static void Main() {
int[] list = {10, 100, 200};
fixed(int* ptr = list) /* 让指针获取数组地址 */
for (int i = 0; i < 3; i++) {
Console.WriteLine("Address of list[{0}]={1}", i, (int)(ptr + i));
Console.WriteLine("Value of list[{0}]={1}", i, *(ptr + i));
}
Console.ReadKey();
}
}
}
编译执行上述代码,输出结果类似:
Address of list[0] = 31627168 Value of list[0] = 10 Address of list[1] = 31627172 Value of list[1] = 100 Address of list[2] = 31627176 Value of list[2] = 200
编译不安全代码
编译不安全代码需在命令行编译器中指定 /unsafe 开关。
例如,编译包含不安全代码的程序 prog1.cs,命令行输入:
csc /unsafe prog1.cs
若使用 Visual Studio IDE,需在项目属性中启用不安全代码:
- 在解决方案资源管理器中双击属性节点打开项目属性。
- 点击生成选项卡。
- 勾选允许不安全代码选项。
C语言