2010-04-17 16 views
14

Tengo dos punteros no administrados en forma de IntPtr y quiero copiar datos entre ellos. ¿Cómo puedo hacer esto? Sé el método Marshal.Copy, pero solo puede copiar entre no administrado y administrado. Y la segunda parte: ¿Copiar datos no administrados desde C# es más lento que hacerlo en C/C++ no administrado utilizando memcpy?¿Cómo puedo copiar datos no administrados en C# y qué tan rápido es?


Editar: estaría especialmente interesado en una plataforma de aplicación independet.

+0

a comentar todas las respuestas dadas hasta ahora: No hay .NET directa (y de la plataforma) manera de hacer esto? – Danvil

+0

He actualizado mi respuesta con el enfoque directo de C# (usando un bloque y punteros inseguros). – Ash

Respuesta

15

Usted puede utilizar la función win32 memcpy través de P-Invocar.

[DllImport("msvcrt.dll", SetLastError = false)] 
static extern IntPtr memcpy(IntPtr dest, IntPtr src, int count); 

Aparte de la (leve) por encima llamar a una función Win32 desde el código administrado, el rendimiento real de la copia debe ser el mismo que el código C/C++ que utiliza la misma función.

No olvide que también puede utilizar un bloque inseguro (y la opción del compilador) y simplemente copiar los datos de un byte/int/larga a la vez:

unsafe 
{ 
    // srcPtr and destPtr are IntPtr's pointing to valid memory locations 
    // size is the number of long (normally 4 bytes) to copy 
    long* src = (long*)srcPtr; 
    long* dest = (long*)destPtr; 
    for (int i = 0; i < size/sizeof(long); i++) 
    { 
     dest[i] = src[i]; 
    } 
} 

Esto elimina la dependencia de la plataforma, pero debe tener mucho cuidado con la comprobación de límites y la aritmética del puntero.

+1

Gracias por el código inseguro, pero mi experiencia C/C++ me advierte, que uno corre en un montón de problemas cuando se trata de volver a implementar memcpy ... – Danvil

+0

@Danvil, sí, el objetivo de usar .NET es evitar un código como este. Puede ser útil para el procesamiento eficiente de mapas de bits, etc., pero debe evitarse si es posible. Sin embargo, es reconfortante que Microsoft todavía admita esta característica de "disparate a ti mismo en el pie" si la necesitas. – Ash

+6

Llamarlo con esta firma provoca un [pInvokeStackImbalance] (http://msdn.microsoft.com/en-us/library/0htdy0k3.aspx) para mí. Pero esto se resolvió utilizando la firma en [pinvoke.net] (http://www.pinvoke.net/default.aspx/msvcrt/memcpy.html). – Aidiakapi

5

Sin hacer comentarios sobre el rendimiento, simplemente porque yo no lo he probado. Puede lograr el mismo rendimiento que la copia no administrada utilizando CopyMemory o MoveMemory desde Kernel32 a través de interoperabilidad.

Aquí está la declaración de CopyMemory

[DllImport("kernel32.dll")] 
static extern void CopyMemory(IntPtr destination, IntPtr source, uint length); 
+1

Creo que CopyMemory y RTLCopyMemory en realidad solo usan memcpy para hacer la copia real. Vea el archivo de encabezado winnt.h – Ash

+0

Sí, terminas en ntdll memcpy. – Trass3r

1

CopyMemory aka aka RtlCopyMemorymemcpy() será igual de rápido si llama desde C# o C (con excepción de la pequeña sobrecarga de PInvoking el método en sí).

Algo a tener en cuenta, sin embargo, es que CopyMemory solo debe utilizarse cuando esté seguro de que los rangos de origen y destino no se superponen. Si se superponen, debe usar MoveMemory, que será más lento.

Aquí es una declaración de CopyMeSomeMemory, mostrando cuántas maneras diferentes se puede hacer lo mismo en .Net:

[DllImport("kernel32.dll", EntryPoint = "RtlCopyMemory")] 
public static extern void CopyMeSomeMemory(IntPtr Destination, 
    IntPtr Source, uint Length); 

Para el registro, creo Buffer.BlockCopy en .Net simplemente envuelve una de estas funciones, también.

4

Si puede orientar .NET 4.6 o superior, tratar System.Buffer.MemoryCopy. Creo que la principal diferencia entre esto y las soluciones de P/Invoke mencionadas anteriormente es que este método evita la P/Invoke para tamaños más pequeños y simplemente hace la copia directamente.

Here's las entrañas de la implementación en .NET Core (la última a partir del momento de este anuncio).

Cuestiones relacionadas