2015-08-11 17 views
5

Se si vuole fare una copia di memoria tra i due array, c'è una funzione Array.Copy per quella in .NET:Esiste un modo portatile per copiare un blocco di memoria in C#?

char[] GetCopy(char[] buf) 
{ 
    char[] result = new char[buf.Length]; 
    Array.Copy(buf, result); 
    return result; 
} 

Questo è di solito più veloce di manuale per-loop per copiare tutti i personaggi buf a result, perché è un'operazione di copia di blocco che prende semplicemente un blocco di memoria e lo scrive nella destinazione.

Analogamente, se invece venisse dato un char* e un int specificando le sue dimensioni, quali sono le mie opzioni? Qui ci sono quelli che ho preso in considerazione:

  • Buffer.BlockCopy: richiede src e dst ad essere matrici
  • Buffer.MemoryCopy: esattamente quello che sto cercando, ma disponibile solo su. NET Desktop
  • Marshal.Copy: ha smesso di essere supportato in .NET 2,0

Oppure, se non c'è alter nativo, c'è un modo per costruire un array da un puntatore char* e una lunghezza int? Se potessi farlo, potrei semplicemente convertire i puntatori in array e passarli in Array.Copy.

Non sto cercando for-loops perché, come ho detto, non sono molto efficienti rispetto alle copie a blocchi, ma se è l'unico modo che credo che dovrebbe fare.

TL; DR: Fondamentalmente sto cercando memcpy(), ma in C# e può essere utilizzato nei PCL.

+0

Avete effettivamente misurato la quantità di memoria manuale di base non sicura di base più lenta (simile a [Buffer.MemoryCopy] (http://referencesource.microsoft.com/#mscorlib/system/buffer.cs,c2ca91c0d34a8f86))? Poiché non ci sono controlli di runtime e il codice risultante è piccolo, non ci dovrebbe essere molta differenza rispetto alle operazioni di spostamento dei blocchi (e in realtà 'memcpy' è spesso solo un loop manuale). –

+0

@AlexeiLevenkov No, ma non dovrebbe essere più veloce uno basato su blocchi? Non sto chiedendo questo perché sono insoddisfatto del manuale del ciclo continuo; Sono solo curioso di sapere se c'è un modo migliore. –

+1

Non ne ho idea, ma dal momento che la copia della memoria è limitata dalla velocità della memoria e dalla CPU, non mi aspetto che il ciclo manuale sia più lento della copia di blocco specifica della CPU. Da notare che quel post richiede l'equivalente di 'memcpy' che non è necessario compilare in istruzioni di copia a blocchi ... Considera di fare il tuo benchmark. Puoi trovare maggiori informazioni sulla copia in domande simili come http://stackoverflow.com/questions/2658380/how-can-i-copy-unmanaged-data-in-c-sharp-and-how-fast-is-it e http://stackoverflow.com/questions/4707012/c-memcpy-vs-stdcopy). –

risposta

2

Si dichiara che Marshal.Copy non sarà più supportato, tuttavia sulla documentazione della classe Marshal non riesco a trovare alcuna indicazione.

Anzi, al contrario, la classe è disponibile per le seguenti versioni quadro: 4.6, 4.5, 4, 3.5, 3.0, 2.0, 1.1

Una possibile implementazione di una funzione di utilità in base a questo metodo sarebbe:

public static void CopyFromPtrToPtr(IntPtr src, uint srcLen, 
            IntPtr dst, uint dstLen) 
{ 
    var buffer = new byte[srcLen]; 
    Marshal.Copy(src, buffer, 0, buffer.Length); 
    Marshal.Copy(buffer, 0, dst, (int)Math.Min(buffer.Length, dstLen)); 
} 

Tuttavia, è del tutto possibile che copiando i byte da IntPtr a byte[] e viceversa nega ogni possibile guadagno prestazioni rispetto appunta la memoria pericoloso e copiandolo in un ciclo.

A seconda di quanto portatile deve essere il codice, è possibile anche considerare l'utilizzo di P/Invoke per utilizzare effettivamente il metodo memcpy. Questo dovrebbe funzionare bene su Windows 2000 e successivi (tutti i sistemi su cui è installata la libreria run-time di Microsoft Visual C).

[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] 
static extern IntPtr memcpy(IntPtr dst, IntPtr src, UIntPtr count); 

Modifica: Il secondo approccio non sarebbe adatto per le librerie di classi portatili, tuttavia il primo sarebbe.

1

Non ricordo le API incorporate del BCL ma è possibile copiare il codice BCL memcpy e usarlo. Usa Reflector e cerca "memcpy" per trovarlo.Il codice non sicuro è perfettamente definito e portatile.