2012-07-16 3 views
5

Il codice modulo sottostante è stata riflessa Net Framework:Perché il codice del metodo Marshal.WriteInt64 è così complesso?

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

A mio parere, *((long*) numPtr) = val è abbastanza, e molto efficiente.

Perché così complesso?

+0

Forse qualcosa a che fare con endiens? . – KingCronus

+5

Sembra più che abbia a che fare con l'allineamento della memoria. –

+0

Questo è memcpy(), srotolato a mano. Necessario su core ARM, credo. –

risposta

6

Sembra piuttosto semplice, anche se ottimizzato.

Si noti l'esterno se - esso controlla se è possibile scrivere l'Int64 in una sola operazione (ciò accade se il puntatore che si tiene il metodo è allineato correttamente - punta all'inizio di un Int64 in memoria - l'indirizzo deve essere un multiplo di 8).

Se non è possibile scrivere in una sola operazione, il codice appena scrive un byte alla volta, saltando il ciclo per risparmiare un po 'di tempo (questo è chiamato 'ciclo di svolgimento')

+0

Suppongo che potrebbero averlo ottimizzato anche per i confini a 4 byte. – leppie

+0

Forse, anche se il controllo in sé potrebbe essere stato troppo costoso per fare una vera differenza in media. – zmbq

+0

'var data = new byte [128]; numero lungo = 0x1234567890ABCDEF; fisso (byte * p = dati) { * (long *) (p + 1) = num; * (long *) (p + 10) = num; } 'Senza il puntatore allineato, questo codice funziona bene. – ldp