2010-03-11 8 views
9

Mi problema es enviar una estructura entre un programa en C a un programa C#.Tamaño de las estructuras en .NET

I hizo una estructura en C#:

public struct NetPoint { 
    public float lat; // 4 bytes 
    public float lon; // 4 bytes 
    public int alt; // 4 bytes 
    public long time; // 8 bytes 
} 

El tamaño total de la estructura debe ser de 20 bytes.

Cuando hago un sizeof() en C++ de esta estructura,

System.Diagnostics.Debug.WriteLine(
    "SizeOf(NetPoint) = " + 
    System.Runtime.InteropServices.Marshal.SizeOf(new NetPoint())); 

la consola de depuración muestra:

SizeOf (NetPoint) = 24

Pero espera que tenga 20 bytes. ¿Por qué veo una diferencia?

+0

Ver aquí: http://www.vsj.co.uk/articles/display.asp?id=501 –

Respuesta

7

En realidad, técnicamente la estructura debe ser un mínimo de 20 bytes. Si asigna más al enviar, el receptor simplemente no los usará/copiará. El problema siempre es la deslocalización.

Dicho esto, veo el problema. Hmm. Creo que el problema es el último tiempo ... que en mi humilde opinión se alinea con ocho bytes, inyectando cuatro bytes vacíos antes. Creo que hay una penalización de rendimiento por tener un elemento de ocho bytes no alineado con un límite de ocho bytes.

Adjunte los atributos StructLayout para determinar el desplazamiento de cada elemento manualmente. Entonces deberías poder hacer las cosas en línea.

Referencia: How to control the physical layout of the data fields in the .NET Framework 2.0

[StructLayout(LayoutKind.Sequential, Pack=1)] 
public struct NetPoint { 
    public float lat; // 4 bytes 
    public float lon; // 4 bytes 
    public int alt; // 4 bytes 
    public long time; // 8 bytes 
} 

Eso al menos debe alinear elementos a un límite de un byte. También puede ir más lejos al definir el inicio exacto de cada elemento, si es necesario.

+0

Su solución también funciona. Muchas gracias. Su solución parece ser más fácil que la respuesta de John. Utilizaré su solución. Adiós – user291830

2

Intente agregar el atributo [StructLayout (LayoutKind.Sequential, Pack = 1)] y vea qué sucede. Sospecho que hay un relleno de 8 bytes, entonces son 3x8 bytes.

+1

no, objeto en .NET (a excepción de los primitivos como int) tiene un tamaño superior a la suma de campos. – Andrey

9

Como regla general, a las CPU les gusta tener variables alineadas en la memoria en una ubicación que es un múltiplo par de su tamaño, por lo que un entero de cuatro bytes debe estar en una dirección de memoria divisible por cuatro y un ocho -byte long debe estar en una dirección divisible por ocho.

Los diseñadores de lenguaje C# (y C++) lo saben, e insertarán relleno en las estructuras para proporcionar la alineación necesaria. Por lo que el diseño real de su estructura se parece a esto:

public struct NetPoint { 
    public float lat;   // 4 bytes Offset 0 
    public float lon;   // 4 bytes Offset 4 
    public int alt;   // 4 bytes Offset 8 
    int to_preserve_alignment; // 4 bytes Offset 12 
    public long time;   // 8 bytes Offset 16 
} 

Puedes solucionar este problema haciendo que el tiempo que el primer valor, por regla general, si siempre pone los valores más grandes en el comienzo de sus estructuras, que ganó No se ha insertado ningún relleno para preservar la alineación de los miembros.

También se puede arreglar añadiendo

[StructLayout(LayoutKind.Sequential, Pack = 4)] 

antes de la declaración de la estructura, sino que dará lugar a mal alineada long time lo que perjudica el rendimiento.En algunas CPU, duele bastante el rendimiento. (El ALPHA AXP podría fallar en miembros desalineados, por ejemplo). x86 Las CPU solo tienen una pequeña penalización de rendimiento, pero existe el peligro de que las futuras CPU tengan una importante penalización de rendimiento, por lo que es mejor diseñar sus estructuras para alinearlas correctamente (en lugar de empaquetarlas) si es posible.

+0

¡Tiene todo derecho! Muchas gracias – user291830

+1

Guau, me encanta este tipo de comentarios. Acabo de aprender algo nuevo e interesante. –

1

TomTom contestó esta pregunta bastante bien, creo, pero hay otra alternativa si termina en una complicada situación de interoperabilidad COM. Cada campo puede alinearse por sí mismo utilizando los atributos FieldOffset.

[StructLayout(LayoutKind.Explicit)] 
public struct COMPoint 
{ 
    [FieldOffset(0)] public int X; 
    [FieldOffset(4)] public int Y; 
} 
Cuestiones relacionadas