这导致AccessViolationException抛出:
using System;
namespace TestApplication
{
internal static class Program
{
private static unsafe void Main()
{
ulong* addr = (ulong*)Int64.MaxValue;
ulong val = *addr;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这会导致NullReferenceException抛出:
using System;
namespace TestApplication
{
internal static class Program
{
private static unsafe void Main()
{
ulong* addr = (ulong*)0x000000000000FF;
ulong val = *addr;
}
}
}
Run Code Online (Sandbox Code Playgroud)
它们都是无效指针,都违反了内存访问规则.为什么NullReferenceException?
Han*_*ant 43
这是由多年前制定的Windows设计决定引起的.地址空间的底部64千字节是保留的.报告使用空引用异常而不是基础访问冲突来访问该范围内的任何地址.这是明智的选择,空指针可以在实际上不为零的地址处产生读取或写入.例如,读取C++类对象的字段时,它与对象的开头有一个偏移量.如果对象指针为null,则代码将在大于0的地址处读取.
C#没有完全相同的问题,语言保证在调用类的实例方法之前捕获空引用.然而,这是特定于语言的,它不是CLR功能.您可以使用C++/CLI编写托管代码并生成非零空指针解引用.在nullptr对象上调用方法有效.该方法将快乐地执行.并调用其他实例方法.在它尝试访问实例变量或调用虚拟方法之前,需要取消引用它,然后kaboom.
C#保证非常好,它使得诊断空引用问题变得更加容易,因为它们是在调用站点生成的,并且不会在嵌套方法中的某处进行轰炸.并且它基本上更安全,当实例变量的偏移量大于64K时,它可能不会触发极大对象的异常.与C++不同,在托管代码中很难做到.但这篇博客文章解释说,这不是免费的.
Ray*_*hen 17
CPU引发空引用异常和访问冲突异常作为访问冲突.然后,CLR必须猜测访问冲突是否应该专门针对空引用异常,还是作为更一般的访问冲突而保留.
从您的结果中可以明显看出,CLR推断出非常接近0的地址处的访问冲突是由空引用引起的.因为它们几乎肯定是由空引用加上字段偏移生成的.你使用不安全的代码愚弄了这种启发式方法.
| 归档时间: |
|
| 查看次数: |
1373 次 |
| 最近记录: |