2012-09-24 43 views
10

Tengo varias estructuras que tienen la disposición secuencial:Marshal.SizeOf en una estructura que contiene GUID da bytes adicionales

struct S1 
{ 
    Guid id; 
} 

struct S2 
{ 
    Guid id; 
    short s; 
} 

struct S3 
{ 
    Guid id; 
    short s; 
    short t; 
} 

Calling Marshal.SizeOf sobre los tipos struct anteriores, que tengo:

Size: 
S1 = 16, as expected. 
S2 = 20, copied an instance to a byte array, it only occupies first 18 bytes. 
S3 = 20. 

Mi pregunta es por eso que el tamaño de S2 es 20 pero no 18. Y este problema solo aparece cuando Guid está en la estructura.

No se ha encontrado ninguna información útil de msdn. Sé Marshal.SizeOf da el tamaño del espacio que el tipo ocupará en la memoria, pero quiero saber por qué se merece 2 bytes adicionales para hacer que el tamaño sea un múltiplo de 4.

¿Y cómo puedo evitar este "problema"?

¡Muchas gracias!

+0

Eche un vistazo a @Hans Passant muy detallada [respuesta] (http://stackoverflow.com/a/3362736/1289454) en el diseño de la memoria de Estructura. Él afirma que 'Marhsal.SizeOf' solo puede proporcionar una estimación aproximada. – gowansg

Respuesta

9

Esto se debe a la implícita [StructLayout] asociada a una estructura, el campo Pack es el más importante. Dicta cómo los miembros de la estructura se alinean después de obtener un marshaled. El valor predeterminado para Pack es 8. Lo que indica que cualquier miembro con un tamaño menor o igual a 8 bytes está alineado. En otras palabras, un corto se alineará con un desplazamiento que es un múltiplo de 2, un int a 4, un largo o doble a 8.

El punto clave es que la alineación debería funcionar cuando se crea una matriz de las estructuras . Más fácil demostrado con un ejemplo más simple:

using System; 
using System.Runtime.InteropServices; 

class Program { 
    static void Main(string[] args) { 
     Console.WriteLine(Marshal.SizeOf(typeof(Example))); 
     Console.ReadLine(); 
    } 
} 
struct Example { 
    public int a; 
    public short b; 
} 

de salida: 8

El miembro a obliga al tamaño que aumentarse, dos bytes de relleno adicionales se añaden a la estructura para asegurar que el int todavía se alinea con un desplazamiento eso es un múltiplo de 4 cuando la estructura se usa en una matriz. Puede cambiar el resultado aplicando el atributo:

[StructLayout(LayoutKind.Sequential, Pack = 2)] 
struct Example { 
    public int a; 
    public short b; 
} 

de salida: 6

El miembro a será ahora mis-alineados cuando la struct se utiliza en una matriz.

Volver a Guid, no se puede ver desde la declaración, pero internamente se compone de una serie de miembros. El primero es un campo privado llamado _a y es un int.El Guid por lo tanto requiere una alineación de 4 bytes. Por lo tanto, se necesitan 2 bytes de relleno adicionales para que su estructura se alinee correctamente cuando se utiliza en una matriz. Necesitarías Pack = 1 o Pack = 2 en S2 para obtener 18 bytes.

Más información sobre las estructuras y la forma especial en que se tratan en .NET en this answer.

+0

Muchas gracias. – user1695516

0

creo que es debido a que algunos elementos deben estar alineados en la memoria de 4 bytes (u 8 bytes) límites. Por lo tanto, la estructura se convierte en un múltiplo de este tamaño para que las matrices de las estructuras estén todas alineadas correctamente. En una máquina de 64 bits que incluye una cadena, se fuerza a un múltiplo de 8 bytes; GUID parece requerir solo un múltiplo de 4 bytes incluso en 64 bits. Si la estructura que contiene un GUID no era un múltiplo de 4 bytes de tamaño, algunos de los GUID no estarían en un límite de 4 bytes en una matriz de estas estructuras. No creo que pueda evitar el "problema", ¿por qué es un problema?

Cuestiones relacionadas