C#指针必须用unsafe关键字,因GC会移动对象导致地址失效;需启用AllowUnsafeBlocks,且仅支持值类型;指针运算不检查边界,易越界,应配合fixed锁定数组。

在 C# 中直接使用指针不是默认行为,必须显式启用不安全上下文,且仅限于特定类型和场景。它不像 C 那样自由,但确实存在、可用、必要——尤其在高性能计算、互操作(P/Invoke)、图像处理或底层内存操作中。
为什么 C# 指针必须写 unsafe
C# 的垃圾回收器(GC)会移动托管对象以优化内存布局,这意味着对象地址可能随时变化。而指针保存的是固定地址,一旦对象被 GC 移动,指针就指向了错误位置,引发未定义行为。所以:
-
unsafe块或unsafe方法是编译器的“免责协议”:你承诺自己管理内存,GC 不再为你兜底 - 项目需开启
AllowUnsafeBlocks(.csproj 中设为true),否则编译直接报错CS0227 - 即使启用了,也不能对
string、object、含引用字段的struct取地址——它们是“托管类型”,地址不可靠
int* 和 void* 怎么声明与初始化
指针声明语法严格:type* 中的 * 属于类型,不是变量名前缀;多个指针要写成 int* p1, p2;,而非 int *p1, *p2;(后者在 C# 中非法)。
常见用法示例:
unsafe
{
int value = 42;
int* ptr = &value; // ✅ 正确:取栈上局部变量地址
Console.WriteLine(*ptr); // 输出 42
<pre class="brush:php;toolbar:false;">int* ptr2 = stackalloc int[3]; // ✅ 在栈上分配内存,无需 GC 管理
ptr2[0] = 1; ptr2[1] = 2;
void* vptr = (void*)ptr; // ✅ 允许转为 void*
// int* bad = (int*)vptr; // ❌ 必须显式强转回具体类型}
注意:stackalloc 分配在当前栈帧,函数返回即自动释放;不能用于类字段或跨方法传递。
指针算术和数组访问为什么容易越界
C# 指针支持 +、-、++、--,但**不检查边界**。比如 int* p = arr; 后,p + 10 可能已超出数组范围,读写会破坏其他变量或触发访问冲突(AV)。
- 指针加 1 表示“跳过一个
int大小”,即 +4 字节(32 位)或 +8 字节(64 位),不是简单 +1 - 对
char*加 1 是 +1 字节,这是字符串逐字节遍历的基础 - 没有内置机制防止
p[-1]或p[1000],调试时建议配合fixed语句锁定数组首地址,并记录长度
推荐模式:
unsafe
{
int[] arr = { 10, 20, 30 };
fixed (int* p = arr) // ? 锁定 arr 在内存中不被 GC 移动
{
for (int i = 0; i < arr.Length; i++)
{
Console.Write(*(p + i) + " "); // 安全:i 范围可控
}
}
}
函数指针在 C# 中怎么替代 delegate
C# **不支持 C 风格的函数指针(如 int (*func)(int))**。所有回调都通过 delegate 或 Func/Action 实现,它们是类型安全、可捕获上下文、受 GC 管理的托管对象。
只有极少数场景需要真正“函数地址”:
- P/Invoke 调用 C DLL 时,若 C 接口要求传入函数指针(如 Windows API 的
EnumWindows),C# 用Marshal.GetFunctionPointerForDelegate()获取地址 - 用
delegate* unmanaged<...></...>(C# 9+)声明非托管函数指针类型,用于零开销互操作,但必须标注unmanaged且参数只能是非托管类型
例如:
delegate* unmanaged<int, int, int> addPtr = &Add; // C# 9+ int result = addPtr(3, 5); // 直接调用,无 delegate 封装开销 <p>static int Add(int a, int b) => a + b;
这个 delegate* 是真正的函数地址,但生命周期需自行管理,不能引用闭包或托管对象。
真正难的不是语法,而是判断什么时候该用指针、什么时候该用 Span<t></t> 或 Memory<t></t> ——后者在绝大多数场景下更安全、更现代,也具备类似性能优势。指针只应在你明确知道 GC 干预会成为瓶颈,且愿意承担全部内存责任时才出手。


















