C# 非4字节对齐时,单触浮点指针引发NullReferenceException
我正面临一个我无法理解的问题 在使用Monotouch在C#中使用不安全指针时,我在设备(ARM)上得到了一个NullReferenceException,但我无法解释原因,让我们来看一些代码C# 非4字节对齐时,单触浮点指针引发NullReferenceException,c#,ios,.net,xamarin.ios,unsafe,C#,Ios,.net,Xamarin.ios,Unsafe,我正面临一个我无法理解的问题 在使用Monotouch在C#中使用不安全指针时,我在设备(ARM)上得到了一个NullReferenceException,但我无法解释原因,让我们来看一些代码 var rand = new Random(); var buffer = new byte[2 * 1024 * 1024]; rand.NextBytes(buffer); fixed (byte* ptr = buffer) { var ptr2 = ptr + 982515;
var rand = new Random();
var buffer = new byte[2 * 1024 * 1024];
rand.NextBytes(buffer);
fixed (byte* ptr = buffer) {
var ptr2 = ptr + 982515;
//This works
var bfr = new byte[8];
for (int i = 0; i < 8; i++)
bfr[i] = ptr2[i];
var v = BitConverter.ToDouble(bfr, 0);
//This throws a NullReferenceException on device
var v2 = *(double*)ptr2;
Console.WriteLine("v: {0}; v2: {1}", v, v2);
}
var rand=new Random();
var buffer=新字节[2*1024*1024];
下一字节随机数(缓冲区);
固定(字节*ptr=缓冲区){
var ptr2=ptr+982515;
//这很有效
var bfr=新字节[8];
对于(int i=0;i<8;i++)
bfr[i]=ptr2[i];
var v=位转换器。ToDouble(bfr,0);
//这会在设备上引发NullReferenceException
变量v2=*(双*)ptr2;
WriteLine(“v:{0};v2:{1}”,v,v2);
}
它只在设备上崩溃。
与手臂结构对齐有关吗
编辑
经过一番研究后,我得出以下结论:
浮点值只能从ARM上的4字节对齐地址读取
static void Main(string[] args) {
Test(982512); //Works
Test(982516); //Works
Test(982515); //Crash on device only
}
unsafe static void Test(int offset) {
var rand = new Random();
var buffer = new byte[2 * 1024 * 1024];
rand.NextBytes(buffer);
fixed (byte* ptr = buffer) {
var ptr2 = ptr + offset;
//Always works
var bfr = new byte[8];
for (int i = 0; i < 8; i++)
bfr[i] = ptr2[i];
var v = BitConverter.ToDouble(bfr, 0);
//Throws a NullReferenceException on device if offset is not 4-byte aligned
var v2 = *(double*)ptr2;
Console.WriteLine("v: {0}; v2: {1}", v, v2);
}
}
static void Main(字符串[]args){
测试(982512);//工作
测试(982516);//工作
测试(982515);//仅在设备上崩溃
}
不安全静态空隙试验(内部偏移){
var rand=new Random();
var buffer=新字节[2*1024*1024];
下一字节随机数(缓冲区);
固定(字节*ptr=缓冲区){
var ptr2=ptr+偏移量;
//总是有效的
var bfr=新字节[8];
对于(int i=0;i<8;i++)
bfr[i]=ptr2[i];
var v=位转换器。ToDouble(bfr,0);
//如果偏移量不是4字节对齐的,则在设备上引发NullReferenceException
变量v2=*(双*)ptr2;
WriteLine(“v:{0};v2:{1}”,v,v2);
}
}
想知道如何绕过这个问题吗?在ARM设备上,只有在4字节对齐的地址上才能取消对浮点值(单、双)的引用 所以解决方案是这样的:
static double ReadDouble(byte* ptr, int offset) {
var ptr2 = ptr + offset;
if ((int)ptr2 % 4 == 0)
return *(double*)ptr2;
else {
var bfr = new byte[8];
for (int i = 0; i < 8; i++)
bfr[i] = ptr2[i];
var v = BitConverter.ToDouble(bfr, 0);
}
}
static double ReadDouble(字节*ptr,int偏移量){
var ptr2=ptr+偏移量;
如果((int)ptr2%4==0)
返回*(双*)ptr2;
否则{
var bfr=新字节[8];
对于(int i=0;i<8;i++)
bfr[i]=ptr2[i];
var v=位转换器。ToDouble(bfr,0);
}
}
您需要发布实际代码-该代码无法编译(buffer
在修复的块中重新声明)。我在固定的块之前定义了buffer
并删除了另一个buffer
声明,我尝试了这段代码,它正常工作,没有任何异常。考虑到这一点,也许您有某种多线程问题?我编辑了代码。如前所述,它并不总是崩溃,但只有一些特定的数据,我将尝试发布一个。如果我再次编辑代码,您现在可以重现崩溃。问题是-显然,(double*)ptr2返回null。然后*ptr2导致异常。。