2012-07-16 18 views
5

Kod formularza poniżej odzwierciedlenie .Net Framework:Dlaczego kod metody Marshal.WriteInt64 jest tak skomplikowany?

[SecurityCritical] 
public static unsafe void WriteInt64(IntPtr ptr, int ofs, long val){ 
    try{ 
     byte* numPtr = (byte*) (((void*) ptr) + ofs); 
     if ((((int) numPtr) & 7) == 0){ 
      *((long*) numPtr) = val; 
     } 
     else{ 
      byte* numPtr2 = (byte*) &val; 
      numPtr[0] = numPtr2[0]; 
      numPtr[1] = numPtr2[1]; 
      numPtr[2] = numPtr2[2]; 
      numPtr[3] = numPtr2[3]; 
      numPtr[4] = numPtr2[4]; 
      numPtr[6] = numPtr2[6]; 
      numPtr[7] = numPtr2[7]; 
     } 
    } 
    catch (NullReferenceException){ 
     throw new AccessViolationException(); 
    } 
} 

Moim zdaniem *((long*) numPtr) = val wystarczy, i bardzo skuteczny.

Dlaczego tak skomplikowane?

+0

Może coś z endiens? . – KingCronus

+5

Wygląda bardziej jak przy wyrównaniu pamięci do mnie. –

+0

To memcpy(), rozwijane ręcznie. Niezbędne w rdzeniach ARM, jak sądzę. –

Odpowiedz

6

Wydaje się dość proste, choć zoptymalizowane.

Zauważ, że zewnętrzna if - sprawdza, czy możesz napisać Int64 w jednej operacji (dzieje się tak, gdy wskaźnik, który podałeś, jest wyrównany, - wskazuje na początek Int64 w pamięci - adres musi być wielokrotnością 8).

Jeśli nie można napisać w jednej operacji, kod po prostu pisze jeden bajt na raz, omijając pętlę, aby zaoszczędzić trochę czasu (nazywa się to „rozwijanie pętli”)

+0

Zgadnij, że mogli zoptymalizować to również dla granic 4-bajtowych. – leppie

+0

Być może, chociaż samo sprawdzenie mogło być zbyt drogie, aby uzyskać średnią różnicę. – zmbq

+0

'var data = new byte [128]; long num = 0x1234567890ABCDEF; poprawiony (bajt * p = dane) { * (długi *) (p + 1) = num; * (długa *) (p + 10) = liczba; } 'Bez wyrównania wskaźnika, ten kod działa dobrze. – ldp

Powiązane problemy