迁移一个旧程序到.net. 之前有段代码是这样的.
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long) For n = 0 To 4 lbt(0) = strRead(n * 4 + 3 + 3) lbt(1) = strRead(n * 4 + 3 + 2) lbt(2) = strRead(n * 4 + 3 + 1) lbt(3) = strRead(n * 4 + 3) CopyMemory ByVal VarPtr(fTempData(n)), ByVal VarPtr(lbt(0)), 4 Next
直接翻译成C#, 结果运行时报错 尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", CharSet = CharSet.Ansi)] public extern static long CopyMemory(IntPtr dest, IntPtr source, int size); for (n = 0; n <= 4; n++) { lbt[0] = bytRead[n * 4 + 3 + 3]; lbt[1] = bytRead[n * 4 + 3 + 2]; lbt[2] = bytRead[n * 4 + 3 + 1]; lbt[3] = bytRead[n * 4 + 3]; CopyMemory ((IntPtr)(fTempData[n]), (IntPtr)(lbt[0]), 4); }
其实这段代码是字节数组转浮点数, 可以用这句代码就可以了 fTempData[n] = BitConverter.ToSingle(lbt, 0);
也可以用 System.Buffer.BlockCopy(lbt, 0, fTempData, 0, 4); 这个不涉及unsafe操作
但这个涉及到内存操作, 之前都没研究过C# unsafe的内存操作. 我还以为只要在项目里打开允许不安全代码.函数里加上unsafe关键字就可以了.结果不是的.
在MSDN找到一段例子
static void Main() { // Create a point struct. Point p; p.x = 1; p.y = 1; Console.WriteLine("The value of first point is " + p.x + " and " + p.y + "."); // Initialize unmanged memory to hold the struct. IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(p)); try { // Copy the struct to unmanaged memory. Marshal.StructureToPtr(p, pnt, false); // Create another point. Point anotherP; // Set this Point to the value of the // Point in unmanaged memory. anotherP = (Point)Marshal.PtrToStructure(pnt, typeof(Point)); Console.WriteLine("The value of new point is " + anotherP.x + " and " + anotherP.y + "."); } finally { // Free the unmanaged memory. Marshal.FreeHGlobal(pnt); } }
一个Memory的类
using System; using System.Runtime.InteropServices; public static unsafe class Memory { // Handle for the process heap. This handle is used in all calls to the // HeapXXX APIs in the methods below. private static readonly IntPtr s_heap = GetProcessHeap(); // Allocates a memory block of the given size. The allocated memory is // automatically initialized to zero. public static void* Alloc(int size) { void* result = HeapAlloc(s_heap, HEAP_ZERO_MEMORY, (UIntPtr)size); if (result == null) throw new OutOfMemoryException(); return result; } // Copies count bytes from src to dst. The source and destination // blocks are permitted to overlap. public static void Copy(void* src, void* dst, int count) { byte* ps = (byte*)src; byte* pd = (byte*)dst; if (ps > pd) { for (; count != 0; count--) *pd++ = *ps++; } else if (ps < pd) { for (ps += count, pd += count; count != 0; count--) *--pd = *--ps; } } // Frees a memory block. public static void Free(void* block) { if (!HeapFree(s_heap, 0, block)) throw new InvalidOperationException(); } // Re-allocates a memory block. If the reallocation request is for a // larger size, the additional region of memory is automatically // initialized to zero. public static void* ReAlloc(void* block, int size) { void* result = HeapReAlloc(s_heap, HEAP_ZERO_MEMORY, block, (UIntPtr)size); if (result == null) throw new OutOfMemoryException(); return result; } // Returns the size of a memory block. public static int SizeOf(void* block) { int result = (int)HeapSize(s_heap, 0, block); if (result == -1) throw new InvalidOperationException(); return result; } // Heap API flags private const int HEAP_ZERO_MEMORY = 0x00000008; // Heap API functions [DllImport("kernel32")] private static extern IntPtr GetProcessHeap(); [DllImport("kernel32")] private static extern void* HeapAlloc(IntPtr hHeap, int flags, UIntPtr size); [DllImport("kernel32")] private static extern bool HeapFree(IntPtr hHeap, int flags, void* block); [DllImport("kernel32")] private static extern void* HeapReAlloc(IntPtr hHeap, int flags, void* block, UIntPtr size); [DllImport("kernel32")] private static extern UIntPtr HeapSize(IntPtr hHeap, int flags, void* block); }
class Test { static unsafe void Main() { byte* buffer = null; try { const int Size = 256; buffer = (byte*)Memory.Alloc(Size); for (int i = 0; i < Size; i++) buffer[i] = (byte)i; byte[] array = new byte[Size]; fixed (byte* p = array) Memory.Copy(buffer, p, Size); for (int i = 0; i < Size; i++) Console.WriteLine(array[i]); } finally { if (buffer != null) Memory.Free(buffer); } } }