问题
I'm facing a problem I just can't understand.
While playing with unsafe pointers in C# with Monotouch, I get a NullReferenceException on device (ARM), but I can't explain why, let's see some code
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);
}
It only crashes on device. Anything to do with ARM structured alignment ?
Edit
After some research I ended with this:
A floating point value can be read only from a 4-bytes aligned address on ARM
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);
}
}
Any idea on how to bypass this ?
回答1:
On ARM devices, dereferencing a floating-point value (Single, Double) is only possible at a 4-bytes aligned address.
http://www.aleph1.co.uk/chapter-10-arm-structured-alignment-faq
So the solution is something like this:
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);
}
}
来源:https://stackoverflow.com/questions/28436327/monotouch-floating-point-pointer-throws-nullreferenceexception-when-not-4-byte-a