我正在使用不安全的代码来解决Code Golf,上的问题,我发现了一些我无法解释的问题。这段代码:
unsafe
{
int i = *(int*)0;
}
发生访问冲突(Segfault)崩溃,但此代码:
unsafe
{
*(int*)0=0;
}
抛出NullReferenceException。在我看来,第一个是执行读取,第二个是执行写入。一个例外告诉我,在操作系统杀死进程之前,CLR中的某个地方正在拦截写入并停止写入。为什么这会在写入时发生,而不是在读取时发生?如果我使指针值足够大,它会在写入时发生段错误。这是否意味着CLR知道的内存块是保留的,甚至不会尝试写入?那么,为什么它允许我尝试从该块读取?我在这里完全误解了什么吗?
有趣的是:System.Runtime.InteropServices.Marshal.WriteInt32(IntPtr.Zero, 0);
给了我一个访问冲突,而不是NullReference。
答案 0 :(得分:4)
第一个例外是有道理的 - 当然 - 你试图从内存地址0读取。第二个更有趣。 :P在C ++中,有一个名为NULL的宏/常量,其值为0.它用于无效的指针地址 - 非常类似于C#中的空值,用于引用类型。由于C#引用是内部指针,因此当您尝试从该地址读取/写入时会发生NullReferenceException - 地址为NULL或0;事实上,0到64K的地址在所有进程(在Windows中)都是无效的,以便捕获程序员的错误。计算机硬件或Windows / .NET Framework版本的确切异常或错误可能略有不同,但两个代码段都会出错。
对于读/写随机地址时的段错误,这是由于操作系统对每个进程的隔离。你不能摆弄其他进程的代码或数据 - 至少不合法。