2015-08-11 42 views
5

Jeśli chcesz zrobić kopię pamięci między dwiema tablicami, istnieje funkcja Array.Copy za to w .NET:Czy istnieje przenośny sposób kopiowania bloku pamięci w języku C#?

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

Zazwyczaj jest to szybciej niż ręcznie-zapętlenie skopiować wszystkie znaki w buf do result, ponieważ jest to operacja kopiowania blokowego, która pobiera porcję pamięci i zapisuje ją do miejsca docelowego.

Podobnie, gdybym zamiast tego otrzymał char* i int określając jego rozmiar, jakie są moje opcje? Oto te, które ja już za:

  • Buffer.BlockCopy: wymaga src i dst być tablice
  • Buffer.MemoryCopy: dokładnie to, czego szukam, ale dostępny tylko na. NET Pulpit
  • Marshal.Copy: przestał być wspierany w .NET 2.0

Lub, jeśli nie ma alter natywny, czy istnieje jakiś sposób na zbudowanie tablicy ze wskaźnika char* i długości int? Gdybym mógł to zrobić, mógłbym zamienić wskaźniki na tablice i przekazać je do Array.Copy.

Nie szukam pętli for, ponieważ, jak powiedziałem, nie są one zbyt wydajne w porównaniu do blokowych kopii, ale jeśli to jedyny sposób, który powinienem wykonać.

TL; DR: Po prostu szukam memcpy(), ale w języku C# i może być używany w PCL.

+0

Czy zmierzyłeś, ile wolniej podstawowej, niebezpiecznej, ręcznej kopii pamięci (podobnie jak [Buffer.MemoryCopy] (http://referencesource.microsoft.com/#mscorlib/system/buffer.cs,c2ca91c0d34a8f86))? Ponieważ nie ma żadnych kontroli w czasie wykonywania, a wynikowy kod jest niewielki, nie powinno być dużych różnic w porównaniu z operacjami przenoszenia bloków (a naprawdę 'memcpy' jest często tylko pętlą ręczną). –

+0

@AlexeiLevenkov Nie, ale czy blokowanie nie powinno być szybsze? Nie pytam o to, ponieważ jestem niezadowolony z ręcznego zapętlania; Po prostu ciekawi mnie, czy istnieje lepszy sposób. –

+1

Nie mam pojęcia, ale ponieważ kopiowanie pamięci jest ograniczone przez szybkość pamięci i procesor, nie oczekiwałbym, że pętla ręczna będzie wolniejsza niż kopia blokowa specyficzna dla procesora. Zauważ, że post pyta o odpowiednik 'memcpy', którego nie trzeba kompilować do instrukcji kopiowania blokowego ... Rozważ wykonanie własnego testu porównawczego. Więcej informacji na temat kopiowania można znaleźć w podobnych pytaniach, takich jak http://stackoverflow.com/questions/2658380/how-can-i-copy-unmanaged-data-in-c-sharp-and-how-fast-is-it i http://stackoverflow.com/questions/4707012/c-memcpy-vs-stdcopy). –

Odpowiedz

2

Podajesz, że Marshal.Copy nie będzie już wspierany, jednak w dokumentacji klasy Marshal nie znajdę na to żadnego wskazania.

Wręcz przeciwnie, klasa jest dostępna w następujących wersjach ramowa: 4,6, 4,5, 4, 3,5, 3,0, 2,0, 1,1

Możliwym implementacja funkcji użyteczności oparte na tej metodzie będzie:

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)); 
} 

jednak jest całkiem możliwe, że kopiowanie bajty z IntPtr do byte[] iz powrotem neguje ewentualnego przyrostu wydajności w stosunku do przypinania pamięć niebezpieczny i skopiowanie go w pętli.

W zależności od tego, jak przenośny musi być kod, można również rozważyć użycie P/Invoke do rzeczywistego użycia metody memcpy. To powinno dobrze działać w systemie Windows 2000 i nowszym (wszystkie systemy z zainstalowaną biblioteką uruchomieniową Microsoft Visual C).

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

Edycja: Drugie podejście nie byłoby odpowiednie dla przenośnych bibliotek klas, pierwsze byłoby jednak.

1

Nie pamiętam, jakie wbudowane funkcje API mają BCL, ale można skopiować kod BCL memcpy i użyć go. Użyj Reflectora i wyszukaj "memcpy", aby go znaleźć.Niebezpieczny kod jest doskonale zdefiniowany i przenośny.