c++ - tener - C: ¿Dónde se usa prácticamente la unión?
hashtags instagram 2018 (18)
Tengo un ejemplo conmigo donde se garantiza la alineación de un tipo, unión max_align. Estoy buscando un ejemplo aún más simple en el que la unión se use de manera práctica, para explicar a mi amigo.
Aquí hay otro ejemplo donde una unión podría ser útil.
(No es mi idea, he encontrado esto en un documento que discute las optimizaciones de c ++ )
comenzar-cita
.... Los sindicatos también pueden usarse para ahorrar espacio, por ejemplo
primero el enfoque no sindicalizado:
void F3(bool useInt) {
if (y) {
int a[1000];
F1(a); // call a function which expects an array of int as parameter
}
else {
float b[1000];
F2(b); // call a function which expects an array of float as parameter
}
}
Aquí es posible usar la misma área de memoria para a y b porque sus rangos de vida no se superponen. Puede guardar una gran cantidad de espacio en la CPU-caché al unir ayb en una unión:
void F3(bool useInt) {
union {
int a[1000];
float b[1000];
};
if (y) {
F1(a); // call a function which expects an array of int as parameter
}
else {
F2(b); // call a function which expects an array of float as parameter
}
}
Usar una unión no es una práctica de programación segura, por supuesto, porque el compilador no recibirá ninguna advertencia si los usos de a y b se superponen. Debe usar este método solo para objetos grandes que ocupan mucho espacio en la caché. ...
end-qoute
Ejemplo:
Al usar diferentes tipos de socket, pero desea un tipo de comon para referirse.
En el mundo de Windows, las unions
se utilizan comúnmente para implementar variantes etiquetadas , que son (o fueron, antes de .NET?) Una forma estándar de pasar datos entre objetos COM .
La idea es que un tipo de union
puede proporcionar una única interfaz natural para pasar datos arbitrarios entre dos objetos. Algunos objetos COM podrían pasarle una variante (por ejemplo, tipo VARIANT
o _variant_t
) que podría contener un double
, float
, int
o lo que sea.
Si tiene que tratar con objetos COM en el código de Windows C ++, verá tipos de variantes por todos lados.
He usado a veces uniones de esta manera
//Define type of structure
typedef enum { ANALOG, BOOLEAN, UNKNOWN } typeValue_t;
//Define the union
typedef struct {
typeValue_t typeValue;
/*On this structure you will access the correct type of
data according to its type*/
union {
float ParamAnalog;
char ParamBool;
};
} Value_t;
Luego, podría declarar matrices de diferentes tipos de valores, almacenar más o menos eficientemente los datos y realizar algunas operaciones "polimorfo" como:
void printValue ( Value_t value ) {
switch (value.typeValue) {
case BOOL:
printf("Bolean: %c/n", value.ParamBool?''T'':''F'');
break;
case ANALOG:
printf("Analog: %f/n", value.ParamAnalog);
break;
case UNKNOWN:
printf("Error, value UNKNOWN/n");
break;
}
}
Las uniones también pueden ser útiles cuando se escribe un juego de palabras , lo cual es deseable en algunos lugares seleccionados (como algunas técnicas para algoritmos de comparación de coma flotante ).
Los sindicatos son útiles si tiene diferentes tipos de mensajes, en cuyo caso no necesita saber en ningún nivel intermedio el tipo exacto. Solo el emisor y el receptor necesitan analizar el mensaje en sí. Cualquier otro nivel solo necesita saber el tamaño y, posiblemente, la información del remitente y / o del receptor.
Otro ejemplo más: guardar haciendo castings.
typedef union {
long int_v;
float float_v;
} int_float;
void foo(float v) {
int_float i;
i.float_v = v;
printf("sign=%d exp=%d fraction=%d", (i.int_v>>31)&1, ((i.int_v>>22)&0xff)-128, i.int_v&((1<<22)-1));
}
en lugar de:
void foo(float v) {
long i = *((long*)&v);
printf("sign=%d exp=%d fraction=%d", (i>>31)&1, ((i>>22)&0xff)-128, i&((1<<22)-1));
}
Para acceder a los registros o puertos de E / S tanto por bit como por bit asignando ese puerto particular a la memoria, vea el ejemplo a continuación:
typedef Union
{
unsigned int a;
struct {
unsigned bit0 : 1,
bit1 : 1,
bit2 : 1,
bit3 : 1,
bit4 : 1,
bit5 : 1,
bit6 : 1,
bit7 : 1,
bit8 : 1,
bit9 : 1,
bit10 : 1,
bit11 : 1,
bit12 : 1,
bit13 : 1,
bit14 : 1,
bit15 : 1
} bits;
} IOREG;
# define PORTA (*(IOREG *) 0x3B)
...
unsigned int i = PORTA.a;//read bytewise
int j = PORTA.bits.bit0;//read bitwise
...
PORTA.bits.bit0 = 1;//write operation
Para mayor comodidad, uso uniones para permitirme usar la misma clase para almacenar valores de xyzw y rgba
#ifndef VERTEX4DH
#define VERTEX4DH
struct Vertex4d{
union {
double x;
double r;
};
union {
double y;
double g;
};
union {
double z;
double b;
};
union {
double w;
double a;
};
Vertex4d(double x=0, double y=0,double z=0,double w=0) : x(x), y(y),z(z),w(w){}
};
#endif
Por lo general, he usado uniones en las que desea tener diferentes vistas de los datos, por ejemplo, un valor de color de 32 bits en el que desea los componentes rojo y verde, azul y alfa de 32 bits
struct rgba
{
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
};
union
{
unsigned int val;
rgba components;
}colorval32;
Nota: también podría lograr lo mismo con el enmascaramiento de bits y el cambio, es decir,
#define GETR(val) ((val&0xFF000000) >> 24)
Pero encuentro el enfoque sindical más elegante.
Recientemente creo que vi una unión usada en la programación de vectores . la programación vectorial se utiliza en tecnología Intel MMX , hardware GPU, Cell Broadband Engine de IBM y otros.
un vector puede corresponder a un registro de 128 bits. Es muy comúnmente utilizado para la arquitectura SIMD . dado que el hardware tiene registros de 128 bits, puede almacenar 4 puntos flotantes de precisión simple en un registro / variable. una forma fácil de construir, convertir, extraer elementos individuales de un vector es usar la unión.
typedef union {
vector4f vec; // processor-specific built-in type
struct { // human-friendly access for transformations, etc
float x;
float y;
float z;
float w;
};
struct { // human-friendly access for color processing, lighting, etc
float r;
float g;
float b;
float a;
};
float arr[4]; // yet another convenience access
} Vector4f;
int main()
{
Vector4f position, normal, color;
// human-friendly access
position.x = 12.3f;
position.y = 2.f;
position.z = 3.f;
position.w = 1.f;
// computer friendly access
//some_processor_specific_operation(position.vec,normal.vec,color.vec);
return 0;
}
si tomas un camino en la programación multinúcleo de PlayStation 3 o la programación de gráficos, es muy probable que te enfrentes a más de estos productos.
Sé que llegué un poco tarde a la fiesta, pero como ejemplo práctico, el tipo de datos Variant
en VBScript está, creo, implementado como una Union
. El siguiente código es un ejemplo simplificado tomado de un artículo que de otra manera se encuentra here
struct tagVARIANT
{
union
{
VARTYPE vt;
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
union
{
LONG lVal;
BYTE bVal;
SHORT iVal;
FLOAT fltVal;
DOUBLE dblVal;
VARIANT_BOOL boolVal;
DATE date;
BSTR bstrVal;
SAFEARRAY *parray;
VARIANT *pvarVal;
};
};
};
La implementación real (como dice el artículo) se encuentra en el archivo de encabezado de oaidl.h .
SDL usa una unión para representar eventos: http://www.libsdl.org/cgi/docwiki.cgi/SDL_Event .
Se pueden encontrar muchos ejemplos de uniones en <X11/Xlib.h>
. Pocos están en algunas pilas IP (en BSD <netinet/ip.h>
por ejemplo).
Como regla general, las implementaciones de protocolo usan union construct.
Te refieres a algo como esto ?
union {
long long a;
unsigned char b[sizeof(long long)];
} long_long_to_single_bytes;
AÑADIDO :
Recientemente utilicé esto en nuestra máquina AIX para transformar el identificador de máquina de 64 bits en una matriz de bytes.
std::string getHardwareUUID(void) {
#ifdef AIX
struct xutsname m; // aix specific struct to hold the 64bit machine id
unamex(&b); // aix specific call to get the 64bit machine id
long_long_to_single_bytes.a = m.longnid;
return convertToHexString(long_long_to_single_bytes.b, sizeof(long long));
#else // Windows or Linux or Solaris or ...
... get a 6byte ethernet MAC address somehow and put it into mac_buf
return convertToHexString(mac_buf, 6);
#endif
Usualmente uso uniones al analizar texto. Yo uso algo como esto:
typedef enum DataType { INTEGER, FLOAT_POINT, STRING } DataType ;
typedef union DataValue
{
int v_int;
float v_float;
char* v_string;
}DataValue;
typedef struct DataNode
{
DataType type;
DataValue value;
}DataNode;
void myfunct()
{
long long temp;
DataNode inputData;
inputData.type= read_some_input(&temp);
switch(inputData.type)
{
case INTEGER: inputData.value.v_int = (int)temp; break;
case FLOAT_POINT: inputData.value.v_float = (float)temp; break;
case STRING: inputData.value.v_string = (char*)temp; break;
}
}
void printDataNode(DataNode* ptr)
{
printf("I am a ");
switch(ptr->type){
case INTEGER: printf("Integer with value %d", ptr->value.v_int); break;
case FLOAT_POINT: printf("Float with value %f", ptr->value.v_float); break;
case STRING: printf("String with value %s", ptr->value.v_string); break;
}
}
Si desea ver cómo se usan los sindicatos HEAVILY, verifique cualquier código usando flex / bison . Por ejemplo, ver splint , contiene TONELADAS de uniones.
struct cat_info
{
int legs;
int tailLen;
};
struct fish_info
{
bool hasSpikes;
};
union
{
fish_info fish;
cat_info cat;
} animal_data;
struct animal
{
char* name;
int animal_type;
animal_data data;
};
- Al leer datos serializados que necesitan ser coaccionados en tipos específicos.
- Al devolver valores semánticos de
lex
ayacc
. (yylval
) - Al implementar un tipo polimórfico, especialmente uno que lee un lenguaje general o DSL
- Cuando se implementa un despachador que específicamente llama a funciones destinadas a tomar diferentes tipos.