2008-09-24 19 views
59

Estoy traduciendo una biblioteca escrita en C++ a C#, y la palabra clave 'union' existe una vez. En una estructuraC++ union en C#

¿Cuál es la forma correcta de traducirlo a C#? Y que hace? Se ve algo como esto;

struct Foo { 
    float bar; 

    union { 
     int killroy; 
     float fubar; 
    } as; 
} 
+0

Puede ser más seguro, pero cuando se interactúa con las bibliotecas C que proporcionan este tipo de estructuras de datos, esta decisión en C# rompe incluso la encapsulación rudimentaria de sus estructuras C/C++. Estoy tratando de lidiar con algo como esto: struct LibrarySType {AnotherType * anotherTypeBuff; int oneSetOfFlags; int anotherSetOfFlags; union {struct {int structMember1; ...} oneUseOfThisLibraryType; struct {char * structMember2; ...} anotherUseOfThisLibraryType; ...} u; int64 * moreStuff; ...entiendes} Ahora no inventé esta estructura de datos inteligente, pero es parte de una API de proveedor Necesito –

Respuesta

63

Puede utilizar diseños de campo explícitos para que:

[StructLayout(LayoutKind.Explicit)] 
public struct SampleUnion 
{ 
    [FieldOffset(0)] public float bar; 
    [FieldOffset(4)] public int killroy; 
    [FieldOffset(4)] public float fubar; 
} 

No probado. La idea es que dos variables tengan la misma posición en su estructura. Por supuesto, solo puedes usar uno de ellos.

Más información sobre los sindicatos en struct tutorial

+2

Tenga en cuenta que esto solo funcionará si los tipos implicados son tipos primitivos (como int y float). Una vez que los objetos están involucrados, no te dejará. – Khoth

+9

¿Funciona con tipos de valores (como enum) o solo tipos primitivos? –

+1

Si tiene otros tipos complejos, el segundo podría ser una propiedad que se convierte a/de la otra. Depende del uso de la Unión y de cómo se usa en otro código que está migrando. – AaronLS

3

En unión C/C++ se utiliza para superponer diferentes miembros en la misma posición de memoria, por lo que si usted tiene una unión de un int y un piso que ambos utilizan los mismos 4 bytes de memoria, obviamente escribir a uno corrompe al otro (ya que int y float tienen diferentes diseños de bits).

Innet. MS fue con la opción más segura y no incluyó esta característica.

EDIT: a excepción de interoperabilidad

+0

que podría ser porque .NET es de nivel superior y es probable que no tenga que preocuparse por serializar datos explícitamente y transferir entre máquinas little-endian y big-endian. Los sindicatos proporcionan una buena forma de convertir, utilizando el truco que se observó en un comentario anterior. – tloach

2

Personalmente, me gustaría pasar por alto la UNIÓN todos juntos y poner en práctica Killroy y Fubar como campos separados

public struct Foo 
{ 
    float bar; 
    int Kilroy; 
    float Fubar; 
} 

Uso de una UNION ahorra 32 bits de memoria asignados por el int. ... no va a hacer o romper una aplicación en estos días.

+7

esto puede no funcionar dependiendo de cómo se accede por otras partes de la biblioteca, en algunos casos puede escribir en una instancia y leer desde el otro para obtener los mismos datos, pero en un formato ligeramente diferente, esa funcionalidad se romperá si lo divide en dos variables distintas – KPexEA

+0

@KPexEA Estoy de acuerdo. Sin embargo, si, por otro lado, es el tipo de unión donde alguna bandera indica cuál de los dos campos es el apropiado, entonces esto funcionará bien. Creo que lo realmente importante es entender el uso y el propósito de la unión en cada caso, antes de decidir cómo portarlo. – AaronLS

22

Realmente no puede decidir cómo lidiar con esto sin saber algo sobre cómo se usa. Si simplemente se usa para ahorrar espacio, entonces puedes ignorarlo y simplemente usar una estructura.

Sin embargo, esa no es la razón por la cual se utilizan uniones. Hay dos razones comunes para usarlos. Una es proporcionar 2 o más formas de acceder a los mismos datos. Por ejemplo, una unión de un int y una matriz de 4 bytes es una (de muchas) maneras de separar los bytes de un entero de 32 bits.

La otra es cuando los datos en la estructura provienen de una fuente externa, como un paquete de datos de red. Por lo general, un elemento de la estructura que contiene la unión es una identificación que le indica qué sabor de la unión está vigente.

En ninguno de estos casos puede ignorar ciegamente la unión y convertirla a una estructura donde los dos (o más) campos no coinciden.

+3

Lo que creo que es importante en la respuesta de Steve, es realmente necesario comprender el uso de la unión particular que está portando. Puede haber otros constructos en C# que satisfagan las necesidades de una manera más elegante. – AaronLS

+0

+1 para los usos típicos – mbx

1

Si está utilizando el union para asignar los bytes de uno de los tipos al otro, entonces en C# puede usar BitConverter.

float fubar = 125f; 
int killroy = BitConverter.ToInt32(BitConverter.GetBytes(fubar), 0); 

o;

int killroy = 125; 
float fubar = BitConverter.ToSingle(BitConverter.GetBytes(killroy), 0);