2012-07-16 12 views
5

El código siguiente formulario se ha reflejado .Net Framework:¿Por qué el código del método Marshal.WriteInt64 es tan complejo?

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

En mi opinión, *((long*) numPtr) = val es suficiente, y muy eficiente.

¿Por qué tan complejo?

+0

Tal vez algo que ver con endiens? . – KingCronus

+5

Parece más como que tiene que ver con la alineación de memoria para mí. –

+0

Eso es memcpy(), desenrollado a mano. Necesario en núcleos ARM, creo. –

Respuesta

6

Parece bastante sencillo, aunque optimizado.

Observe si el if-it externo comprueba si puede escribir el Int64 en una operación (eso sucede si el puntero al que le pasa el método está alineado correctamente - señala el inicio de un Int64 en la memoria) la dirección necesita ser un múltiplo de 8).

Si no se puede escribir en una sola operación, el código simplemente escribe un byte a la vez, sin esperar bucle para ahorrar algo de tiempo (esto se llama 'desenrollado del bucle')

+0

Supongo que también podrían haberlo optimizado para límites de 4 bytes. – leppie

+0

Tal vez, aunque el cheque en sí mismo podría haber sido demasiado caro para hacer una diferencia real en promedio. – zmbq

+0

'var data = new byte [128]; long num = 0x1234567890ABCDEF; fijo (byte * p = datos) { * (long *) (p + 1) = num; * (largo *) (p + 10) = num; } 'Sin puntero alineado, este código funciona bien. – ldp

Cuestiones relacionadas