You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中引用类型的不安全指针实际指向何处?

C#引用类型不安全指针的指向问题

我们先结合两段代码的表现,明确引用类型不安全指针的实际指向:

代码示例1:赋值null后触发空引用异常

static unsafe void Main(string[] args)
{
    var student = new Student { Name = "Dan", Age = 34 };
    
    Student* myStdPtr = &student;

    student = null;
    Console.WriteLine(myStdPtr->Name);
}

class Student
{
    public string Name;
    public int Age;
}

运行这段代码时,访问myStdPtr->Name会抛出NullReferenceException。本质原因是:Student*指针指向的是栈上存储student引用的内存地址。当把student赋值为null时,栈上的这个引用被覆盖成了空指针,后续通过myStdPtr解引用时,相当于间接访问了一个空引用,自然触发异常。

代码示例2:返回栈指针后仍能运行(未定义行为)

static unsafe void Main(string[] args)
{
    Student* student = getStudent();
    Console.WriteLine(student->Name);
}
static unsafe Student* getStudent()
{
    var student = new Student { Name = "Dan", Age = 34 };
    Student* studentPtr = &student;
    return studentPtr;
}
class Student
{
    public string Name;
    public int Age;
}

这段代码能正常运行是一种未定义行为,并非指针指向了堆对象。getStudent方法返回的指针指向的是该方法栈帧里的student引用(栈内存),方法返回后栈帧被回收,这块内存已经不属于当前有效范围。只是运行时栈内存还没被新数据覆盖,所以临时能读出正确值——这是偶然情况,一旦后续有操作覆盖这块内存,访问就会出错。

核心结论

在C#中,为引用类型创建unsafe指针时,指针始终指向的是存储该引用的内存位置(通常是栈上的局部变量,或是堆上的某个字段),而不是直接指向堆上的对象实例本身。

引用类型的实例本身位于堆上,而引用(底层是类似指针的结构)存储在栈或堆的字段中。当你用&取引用类型变量的地址时,得到的是这个引用的存储地址,而非实例的地址。如果要直接获取堆上实例的地址,需要借助__makeref、PtrToStructure这类特殊API;只有值类型的指针才会直接指向实例本身(因为值类型实例直接存储在栈或字段所在的内存中)。

内容的提问来源于stack exchange,提问作者Marcin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 14:36:24