2009-07-21 23 views
9

Tengo una pequeña pregunta sobre las estructuras con el conjunto de atributos LayoutKind.Explicit. Declaré el struct como puede ver, con un fieldTotal con 64 bits, siendo fieldFirst los primeros 32 bytes y fieldSecond los últimos 32 bytes. Después de establecer fieldfirst y fieldSecond en Int32.MaxValue, esperaría que fieldTotal fuera , lo que en realidad no ocurre. ¿Por qué es esto? Sé que C# realmente no es compatible con las uniones C++, tal vez solo leerá bien los valores cuando interopera, pero cuando tratamos de establecer los valores nosotros mismos, ¿simplemente no lo manejaremos realmente bien?¿Cómo puedo simular una unión C++ en C#?

[StructLayout(LayoutKind.Explicit)] 
struct STRUCT { 
    [FieldOffset(0)] 
    public Int64 fieldTotal; 

    [FieldOffset(0)] 
    public Int32 fieldFirst; 

    [FieldOffset(32)] 
    public Int32 fieldSecond; 
} 

     STRUCT str = new STRUCT(); 
     str.fieldFirst = Int32.MaxValue; 
     str.fieldSecond = Int32.MaxValue; 
     Console.WriteLine(str.fieldTotal); // <----- I'd expect both these values 
     Console.WriteLine(Int64.MaxValue); // <----- to be the same. 
     Console.ReadKey(); 

Respuesta

10

La razón es que FieldOffsetAttribute toma un número de bytes como parámetro, no número de bits. Esto funciona como se esperaba:

[StructLayout(LayoutKind.Explicit)] 
struct STRUCT 
{ 
    [FieldOffset(0)] 
    public Int64 fieldTotal; 

    [FieldOffset(0)] 
    public Int32 fieldFirst; 

    [FieldOffset(4)] 
    public Int32 fieldSecond; 
} 
+0

Además de lo que dicen Reed y Jared sobre firmado contra unsigned. –

6

En cuanto a los valores hex si Int32.MaxValue y Int64.MaxValue deben proporcionar la respuesta.

La clave es el bit más significativo. Para un entero positivo, el bit más significativo solo se establece para un número negativo. Entonces, el valor máximo de Int32 es un 0 seguido de una serie completa de 1s. El orden no es importante, solo que habrá al menos un único bit de 0. Lo mismo es cierto para Int64.MaxValue.

Ahora considere cómo debería funcionar una unión. En esencia, expondrá los bits de los valores uno al lado del otro. Entonces ahora tiene un conjunto de bits de 64 de longitud que contiene dos valores de 0 bit. Uno para cada instancia de Int32.MaxValue. Esto nunca puede ser igual a Int64.MaxValue ya que puede contener solo un bit 0.

Por extraño que parezca, probablemente obtendrá el comportamiento que está buscando si establece fieldSecond en Int32.MinValue.

EDIT Se perdió la necesidad de que sea FieldOffset (4) también.

4

Ben M siempre que uno de los elementos más importantes - su definición no está configurado correctamente.

Dicho esto, esto no funcionará, incluso en C++ con una unión. Los valores que especificó no serán (y no deberían ser) los mismos valores, ya que está utilizando entradas firmadas (no sin firmar). Con un int firmado (Int32), tendrá un bit 0 seguido de 1 bit. Cuando hagas la unión, terminarás con un bit de 0, seguido de un montón de 1 bit, luego otro bit de 0, luego un montón de 1 bit ... El segundo bit de 0 es lo que te está arruinando.

Si utilizó UInt32/UInt64, esto funcionaría propiedad, ya que el bit de signo adicional no existe.

+0

Sí, tienes razón. Con lo que dijiste y Ben dijo, funciona como se esperaba. ¡Gracias! –