uniones lenguaje estructuras ejemplos dev arreglo array anidadas c data-structures struct unions

lenguaje - Ventajas de usar union cuando se puede hacer lo mismo usando struct-C



estructuras en c pdf (11)

Como se mencionó antes: los sindicatos ahorran memoria. Pero esta no es la única diferencia. Los estímulos están hechos para guardar TODOS los subtipos dados mientras que las uniones están hechas para guardar EXACTAMENTE UNO de los subtipos dados. Por lo tanto, si desea almacenar un número entero o un número flotante, es probable que una unión sea lo que necesita (pero debe recordar en algún otro lugar qué tipo de número ha guardado). Si quieres almacenar ambos, entonces necesitas una estructura.

Tengo dificultades para entender el uso de la union en C. He leído muchas publicaciones aquí en SO sobre el tema. Pero ninguno de ellos explica por qué se prefiere la union cuando se puede lograr lo mismo usando una estructura.

Citando de K & R

Como ejemplo, como podría encontrarse en un administrador de tablas de símbolos de compilación, supongamos que una constante puede ser un int, un float o un puntero de carácter. El valor de una constante particular debe almacenarse en una variable del tipo apropiado; sin embargo, es más conveniente para la administración de la tabla si el valor ocupa la misma cantidad de almacenamiento y se almacena en el mismo lugar, independientemente de su tipo. Este es el propósito de una unión, una variable única que legítimamente puede contener cualquiera de varios tipos. La sintaxis se basa en estructuras:

union u_tag { int ival; float fval; char *sval; } u;

El uso será

if (utype == INT) printf("%d/n", u.ival); if (utype == FLOAT) printf("%f/n", u.fval); if (utype == STRING) printf("%s/n", u.sval); else printf("bad type %d in utype/n", utype);

Lo mismo se puede implementar usando una estructura. Algo como,

struct u_tag { utype_t utype; int ival; float fval; char *sval; } u; if (u.utype == INT) printf("%d/n", u.ival); if (u.utype == FLOAT) printf("%f/n", u.fval); if (u.utype == STRING) printf("%s/n", u.sval); else printf("bad type %d in utype/n", utype);

¿No es esto lo mismo? ¿Qué ventaja da la union ?

¿Alguna idea?


El lenguaje ofrece al programador numerosas facilidades para aplicar abstracciones de alto nivel a los datos y operaciones de la máquina de nivel más bajo.

Sin embargo, la mera presencia de algo no sugiere automáticamente que su uso sea una mejor práctica. Su presencia hace que el lenguaje sea poderoso y flexible. Pero las necesidades de la industria condujeron al desarrollo de técnicas de programación que favorecían la claridad y el mantenimiento con respecto a la mejor eficiencia de almacenamiento o de eficiencia del código posible.

Entonces, si el conjunto de soluciones de un problema contiene uniones y estructuras, es responsabilidad del programador decidir si la necesidad de un almacenamiento compacto supera los costos.

En los últimos tiempos, el costo de la memoria ha sido extremadamente bajo. La introducción del tipo de bool (e incluso antes de eso, las variables int) permitió a un programador de sistemas de 32 bits utilizar 32 bits para representar un estado binario. Lo ve con frecuencia en la programación a pesar de que un programador podría usar máscaras y obtener 32 valores verdadero / falso en una variable.

Entonces, para responder a su pregunta, la unión ofrece un almacenamiento más compacto para una sola entidad de valor de entre varios tipos posibles que una estructura tradicional, pero a costa de la claridad y posibles defectos sutiles del programa.


El uso de uniones para ahorrar memoria no se realiza en los sistemas modernos, ya que el código para acceder a un miembro de la unión ocupará rápidamente más espacio (y será más lento) que simplemente agregar otra variable de tamaño de palabra a la memoria. Sin embargo, cuando su código tiene que admitir múltiples arquitecturas con endiannesses diferentes (¿qué palabra?), Los sindicatos pueden ser útiles. Tiendo a preferir usar una biblioteca de utilidades endian ( a funciones), pero a algunas personas les gustan los sindicatos.

Los registros de hardware mapeados en memoria también son comúnmente accedidos por los sindicatos. Los campos de bits en C (no los usa, son malos) se pueden pasar como palabras usando uniones.


En el ejemplo que publicó, el tamaño de unión sería el tamaño de float (suponiendo que sea el más grande, como se señala en los comentarios, puede variar en un compilador de 64 bits), mientras que el tamaño de struct sería la suma de tamaños de float, int, char * y utype_t (y relleno, si hay alguno).

Los resultados en mi compilador:

union u_tag { int ival; float fval; char *sval; }; struct s_tag { int ival; float fval; char *sval; }; int main() { printf("%d/n", sizeof(union u_tag)); //prints 4 printf("%d/n", sizeof(struct s_tag)); //prints 12 return 0; }


Los sindicatos se utilizan para guardar solo un tipo de datos a la vez. Si se reasigna un valor, se sobrescribe el valor anterior y no se puede acceder a él. En su ejemplo, los miembros int, float y char pueden tener diferentes valores en cualquier momento cuando se usan como struct. No es el caso en unión. Por lo tanto, depende de los requisitos y el diseño de su programa. Consulte este artículo sobre cuándo usar la unión. Google puede dar incluso más resultados.


Union usa menos memoria y te permite hacer cosas más peligrosas. Representa un bloque continuo de memoria, que puede interpretarse como un entero, un valor de coma flotante o un puntero de carácter.


los sindicatos tienen dos usos dominantes:

Lo primero es proporcionar un tipo de variante, como ha descrito. En contraste con el enfoque struct, hay una unidad de memoria compartida entre todos los miembros de la unión. Si la memoria no es un problema, una estructura también servirá para esta función.

Normalmente incrusto la unión en la estructura: la estructura garantiza que el tipo y los datos se almacenen juntos, y la unión significa que hay exactamente un valor almacenado.

struct any_tag { utype_t utype; union { int ival; float fval; char *sval; } u; } data;

En segundo lugar, una unión tiene un gran uso para el acceso de bajo nivel a datos sin procesar, reinterpretando un tipo como otro. El propósito para el que he usado esto es leer y escribir datos codificados en binario.

float ConvertByteOrderedBufferTo32bitFloat( char* input ) { union { float f; unsigned char buf[4]; } data; #if WORDS_BIGENDIAN == 1 data.buf[0] = input[0]; data.buf[1] = input[1]; data.buf[2] = input[2]; data.buf[3] = input[3]; #else data.buf[0] = input[3]; data.buf[1] = input[2]; data.buf[2] = input[1]; data.buf[3] = input[0]; #endif return dat1.f; }

Aquí, puede escribir en los bytes individuales, dependiendo de la endiancia de la plataforma, luego interpretar esos 4 bytes de char sin procesar como un flotante IEEE. Lanzar esa matriz de caracteres para flotar no tendría el mismo resultado.


tomando prestado de la cita que publicó "... cualquiera de varios tipos ..." de los miembros del sindicato a la vez. Eso es exactamente lo que es la unión; mientras que los miembros de struct se pueden asignar y acceder a la vez.

union tiene más sentido al hacer algunos programas de nivel de sistema (os) como comunicaciones de proceso / manejo de concurrencia.


Los sindicatos son difíciles. Durante años, no pude descifrarlos, luego comencé a hacer cosas con los protocolos de red, y alguien me mostró la luz. Digamos que tiene un encabezado, y luego después del encabezado, hay varios tipos diferentes de paquetes, algo como:

| tipo (4 bytes) | uid (8 bytes) | longitud de carga útil (2 bytes) | Carga útil (longitud variable) |

Y luego habría varios tipos de paquetes de carga ... Por el bien del argumento, podría haber hola, adiós y paquetes de mensajes ...

Bueno, puedes construir un conjunto anidado de estructuras / uniones que puedan representar exactamente un paquete en ese protocolo, así que ...

struct packet { uint type; char unique_id [8]; ushort payload_length; union payload { struct hello { ushort version; uint status; }; struct goodbye { char reason[20]; uint status; }; struct message { char message[100]; }; }; };

Inevitablemente, obtiene este protocolo del sistema operativo a través de una llamada de lectura (), y es solo una mezcla de bytes. Pero si tiene cuidado con la definición de su estructura, y todos los tipos tienen el tamaño correcto, simplemente puede hacer un puntero a la estructura, señalarlo en su memoria intermedia llena de datos aleatorios, y ...

char buf[100]; packet *pkt; read(outsideworld,&buf,1000); pkt = (struct packet *)&buf;

y leer tus paquetes es tan simple como ...

switch(pkt->type){ case PACKET_MESSAGE: printf("message = %s/n", pkt->payload.message.message); break; case PACKET_HELLO: printf("hello! version = %d status = %d/n", pkt->payload.hello.version, pkt->payload.hello.status); break; case PACKET_GOODBYE: printf("goodbye! reason = %s status = %d/n", pkt->payload.goodbye.reason, pkt->payload.goodbye.status); break; }

Sin rodeos, contando bytes, etc. Puedes anidar esto tan profundamente como quieras (crea una unión para direcciones IP, que te da todo como unsigned int, o los bytes individuales para que sea más fácil imprimir 192.168. 0.1 de ella).

Las uniones no ralentizan su código, porque todo se traduce en compensaciones en código de máquina.


Un ejemplo tendría sentido aquí. Vea el ejemplo a continuación:

union xReg { uint allX; struct { uint x3 : 9; uint x2 : 9; uint x1 : 14; }; };

uint es un typedef de unsigned int.

Aquí, esta unión representa un registro de 32 bits. Puedes leer el registro usando allX, y luego manipularlo usando struct.

Esto se alivia de los cambios de bit innecesarios si usamos allX para la manipulación de bits.


Los sindicatos se pueden usar cuando no se necesita acceder a más de un miembro a la vez. De esta forma, puedes guardar algo de memoria en lugar de usar una estructura.

Hay un "truco" ordenado que puede ser posible con uniones: escribiendo un campo y leyendo de otro, para inspeccionar patrones de bits o interpretarlos de manera diferente.