Diferencia entre una estructura y una unión

¿Hay algún buen ejemplo para dar la diferencia entre una struct y una union ? Básicamente sé que struct usa toda la memoria de su miembro y la union usa el espacio de memoria más grande para los miembros. ¿Hay alguna otra diferencia de nivel del sistema operativo?

Con una unión, se supone que solo debes usar uno de los elementos, ya que todos están almacenados en el mismo lugar. Esto lo hace útil cuando desea almacenar algo que podría ser uno de varios tipos. Una estructura, por otro lado, tiene una ubicación de memoria separada para cada uno de sus elementos y todos pueden usarse a la vez.

Para dar un ejemplo concreto de su uso, hace un tiempo estaba trabajando en un intérprete de Scheme y esencialmente estaba superponiendo los tipos de datos de Scheme a los tipos de datos de C. Esto implicó almacenar en una estructura y enum indicando el tipo de valor y una unión para almacenar ese valor.

 union foo { int a; // can't use both a and b at once char b; } foo; struct bar { int a; // can use both a and b simultaneously char b; } bar; union foo x; xa = 3; // OK xb = 'c'; // NO! this affects the value of xa! struct bar y; ya = 3; // OK yb = 'c'; // OK 

editar: si se pregunta qué ajuste xb a ‘c’ cambia el valor de xa a, técnicamente hablando no está definido. En la mayoría de las máquinas modernas, un char es de 1 byte y un int es de 4 bytes, por lo que al darle xb el valor ‘c’ también le da al primer byte de xa el mismo valor:

 union foo x; xa = 3; xb = 'c'; printf("%i, %i\n", xa, xb); 

huellas dactilares

 99, 99 

¿Por qué los dos valores son los mismos? Debido a que los últimos 3 bytes del int 3 son todos cero, por lo que también se lee como 99. Si ponemos un número mayor para xa, verá que este no es siempre el caso:

 union foo x; xa = 387439; xb = 'c'; printf("%i, %i\n", xa, xb); 

huellas dactilares

 387427, 99 

Para ver más de cerca los valores reales de la memoria, establezcamos e imprimamos los valores en hexadecimal:

 union foo x; xa = 0xDEADBEEF; xb = 0x22; printf("%x, %x\n", xa, xb); 

huellas dactilares

 deadbe22, 22 

Puedes ver claramente dónde el 0x22 sobrescribió el 0xEF.

PERO

En C, el orden de los bytes en un int no está definido. Este progtwig sobrescribió el 0xEF con 0x22 en mi Mac, pero hay otras plataformas en las que sobreescribiría el 0xDE porque el orden de los bytes que componen el int se invirtió. Por lo tanto, al escribir un progtwig, nunca debe confiar en el comportamiento de sobreescribir datos específicos en una unión porque no es portátil.

Para obtener más información sobre el orden de los bytes, consulte endianness .

Aquí está la respuesta corta: una estructura es una estructura de registro: cada elemento en la estructura asigna un nuevo espacio. Entonces, una estructura como

 struct foobarbazquux_t { int foo; long bar; double baz; long double quux; } 

asigna al menos (sizeof(int)+sizeof(long)+sizeof(double)+sizeof(long double)) bytes en memoria para cada instancia. (“Al menos” porque las restricciones de alineación de la architecture pueden forzar al comstackdor a rellenar la estructura).

Por otra parte,

 union foobarbazquux_u { int foo; long bar; double baz; long double quux; } 

asigna un trozo de memoria y le da cuatro alias. Así sizeof(union foobarbazquux_u) ≥ max((sizeof(int),sizeof(long),sizeof(double),sizeof(long double)) , de nuevo con la posibilidad de alguna adición para alineaciones.

¿Hay algún buen ejemplo para dar la diferencia entre una ‘estructura’ y una ‘unión’?

Un protocolo de comunicaciones imaginario

 struct packetheader { int sourceaddress; int destaddress; int messagetype; union request { char fourcc[4]; int requestnumber; }; }; 

En este protocolo imaginario, se ha especificado que, en función del “tipo de mensaje”, la siguiente ubicación en el encabezado será un número de solicitud o un código de cuatro caracteres, pero no ambos. En resumen, las uniones permiten que la misma ubicación de almacenamiento represente más de un tipo de datos, donde se garantiza que solo deseará almacenar uno de los tipos de datos en cualquier momento.

Los sindicatos son en gran parte un detalle de bajo nivel basado en el legado de C como lenguaje de progtwigción del sistema, donde a veces se usan ubicaciones de almacenamiento “superpuestas”. A veces puede usar uniones para guardar memoria donde tiene una estructura de datos donde solo se guardará uno de varios tipos a la vez.

En general, al sistema operativo no le importa ni conoce las estructuras y uniones, sino que son simplemente bloques de memoria para él. Una estructura es un bloque de memoria que almacena varios objetos de datos, donde esos objetos no se superponen. Una unión es un bloque de memoria que almacena varios objetos de datos, pero solo tiene almacenamiento para el más grande de ellos, y por lo tanto solo puede almacenar uno de los objetos de datos en cualquier momento.

Como ya indica en su pregunta, la principal diferencia entre union y struct es que union miembros de la union se superponen mutuamente para que el tamaño de una unión sea el mismo, mientras que los miembros de la struct se presentan uno después del otro (con relleno opcional entre). También una unión es lo suficientemente grande como para contener a todos sus miembros, y tienen una alineación que se adapta a todos sus miembros. Digamos que int solo se puede almacenar en direcciones de 2 bytes y tiene 2 bytes de ancho, y long solo se puede almacenar en direcciones de 4 bytes y tiene 4 bytes de longitud. La siguiente unión

 union test { int a; long b; }; 

podría tener un sizeof de 4 y un requisito de alineación de 4. Tanto una unión como una estructura pueden tener relleno al final, pero no al principio. Escribir en una estructura solo cambia el valor del miembro escrito. Escribir a un miembro de una unión invalidará el valor de todos los demás miembros. No puede acceder a ellos si no les ha escrito antes, de lo contrario, el comportamiento no está definido. GCC proporciona una extensión que puede leer de los miembros de una unión, aunque no haya escrito más recientemente. Para un sistema de operación, no tiene que importar si un progtwig de usuario escribe en una unión o en una estructura. Esto en realidad solo es un problema del comstackdor.

Otra propiedad importante de union y struct es que permiten que un puntero a ellos pueda señalar tipos de cualquiera de sus miembros . Entonces el siguiente es válido:

 struct test { int a; double b; } * some_test_pointer; 

some_test_pointer puede apuntar a int* o bool* . Si asigna una dirección de tipo test a int* , apuntará a su primer miembro, a , en realidad. Lo mismo es cierto para una unión también. Por lo tanto, debido a que una unión siempre tendrá la alineación correcta, puede usar una unión para hacer que apunte a algún tipo válido:

 union a { int a; double b; }; 

Esa unión realmente podrá apuntar a un int, y un doble:

 union a * v = (union a*)some_int_pointer; *some_int_pointer = 5; v->a = 10; return *some_int_pointer; 

es realmente válido, como lo establece el estándar C99:

Un objeto debe tener acceso a su valor almacenado solo mediante una expresión lvalue que tenga uno de los siguientes tipos:

  • un tipo compatible con el tipo efectivo del objeto
  • un agregado o tipo de unión que incluye uno de los tipos antes mencionados entre sus miembros

El comstackdor no optimizará v->a = 10; ya que podría afectar el valor de *some_int_pointer (y la función devolverá 10 lugar de 5 ).

Una union es útil en un par de escenarios. union puede ser una herramienta para la manipulación de muy bajo nivel, como escribir controladores de dispositivos para un kernel.

Un ejemplo de esto es la disección de un número float mediante la union de una struct con campos de bit y un float . Guardo un número en el float , y luego puedo acceder a partes particulares del float través de esa struct . El ejemplo muestra cómo se usa la union para tener diferentes angularjs para mirar los datos.

 #include  union foo { struct float_guts { unsigned int fraction : 23; unsigned int exponent : 8; unsigned int sign : 1; } fg; float f; }; void print_float(float f) { union foo ff; ff.f = f; printf("%f: %d 0x%X 0x%X\n", f, ff.fg.sign, ff.fg.exponent, ff.fg.fraction); } int main(){ print_float(0.15625); return 0; } 

Eche un vistazo a la descripción de precisión simple en wikipedia. Usé el ejemplo y el número mágico 0.15625 desde allí.


union también se puede utilizar para implementar un tipo de datos algebraicos que tiene múltiples alternativas. Encontré un ejemplo de eso en el libro “Real World Haskell” de O’Sullivan, Stewart y Goerzen. Compruébelo en la sección La unión discriminada .

¡Aclamaciones!

unión ” y ” estructura ” son construcciones del lenguaje C. Hablar de una diferencia de “nivel de SO” entre ellos es inapropiado, ya que es el comstackdor el que produce código diferente si usa una u otra palabra clave.

No técnicamente hablando significa:

Suposición: silla = bloque de memoria, personas = variable

Estructura : si hay 3 personas pueden sentarse en la silla de su tamaño correspondiente.

Unión : si hay 3 personas, solo habrá una silla para sentarse, todas deben usar la misma silla cuando quieran sentarse.

Técnicamente hablando significa:

El progtwig mencionado más abajo ofrece una profunda inmersión en la estructura y la unión.

 struct MAIN_STRUCT { UINT64 bufferaddr; union { UINT32 data; struct INNER_STRUCT{ UINT16 length; UINT8 cso; UINT8 cmd; } flags; } data1; }; 

Total MAIN_STRUCT size = sizeof (UINT64) para bufferaddr + sizeof (UNIT32) para unión + 32 bit para relleno (depende de la architecture del procesador) = 128 bits. Para la estructura, todos los miembros obtienen el bloque de memoria contiguamente.

Union obtiene un bloque de memoria del miembro de tamaño máximo (Aquí es 32 bits). Dentro de la unión, una estructura más se encuentra (INNER_STRUCT) y sus miembros obtienen un bloque de memoria de un tamaño total de 32 bits (16 + 8 + 8). En unión, se puede acceder al miembro o datos INNER_STRUCT (32 bit) (32 bit).

Sí, la principal diferencia entre struct y union es la misma que usted indicó. Struct usa toda la memoria de su miembro y la unión usa el espacio de memoria más grande para los miembros.

Pero toda la diferencia radica en la necesidad de uso de la memoria. El mejor uso de la unión se puede ver en los procesos de Unix donde hacemos uso de señales. como un proceso puede actuar sobre una sola señal a la vez. Entonces la statement general será:

 union SIGSELECT { SIGNAL_1 signal1; SIGNAL_2 signal2; ..... }; 

En este caso, el proceso utiliza solo la memoria más alta de todas las señales. pero si usa struct en este caso, el uso de la memoria será la sum de todas las señales. Hace una gran diferencia.

Para resumir, Union debe seleccionarse si sabe que tiene acceso a cualquiera de los miembros a la vez.

Una estructura asigna el tamaño total de todos los elementos en él.

Una unión solo asigna tanta memoria como requiera su miembro más grande.

Lo tienes, eso es todo. Pero entonces, básicamente, ¿cuál es el punto de las uniones?

Puede poner el mismo contenido de ubicación de diferentes tipos. Tienes que saber el tipo de lo que has almacenado en la unión (tan a menudo lo pones en una struct con una etiqueta de tipo …).

¿Porque es esto importante? No realmente para ganar espacio. Sí, puedes ganar algunas partes o hacer algo de relleno, pero ese no es el punto principal nunca más.

Es para la seguridad del tipo, te permite hacer algún tipo de “tipado dynamic”: el comstackdor sabe que tu contenido puede tener diferentes significados y el significado preciso de cómo interpretarlo depende de ti en el tiempo de ejecución. Si tiene un puntero que puede apuntar a diferentes tipos, DEBE usar una unión, de lo contrario su código puede ser incorrecto debido a problemas de aliasing (el comstackdor se dice a sí mismo “oh, solo este puntero puede apuntar a este tipo, así puedo optimizar fuera de esos accesos … “, y cosas malas pueden suceder).

Los usos de las Uniones Sindicales se utilizan con frecuencia cuando se necesitan conversaciones tipo especializadas. Para tener una idea de la utilidad de la unión. La biblioteca estándar de c / c no define ninguna función específicamente diseñada para escribir enteros cortos en un archivo. El uso de Fwrite () provoca una sobrecarga excesiva para una operación simple. Sin embargo, al usar una unión, puede crear fácilmente una función que escribe binarios de un entero corto en un archivo de un byte a la vez. Supongo que los enteros cortos tienen 2 bytes de longitud

EL EJEMPLO:

 #include union pw { short int i; char ch[2]; }; int putw(short int num, FILE *fp); int main (void) { FILE *fp; fp fopen("test.tmp", "wb "); putw(1000, fp); /* write the value 1000 as an integer*/ fclose(fp); return 0; } int putw(short int num, FILE *fp) { pw word; word.i = num; putc(word.c[0] , fp); return putc(word.c[1] , fp); } 

aunque putw () llamé con entero corto, era posible usar putc () y fwrite (). Pero quería mostrar un ejemplo para dominar cómo se puede usar una unión

la estructura es una colección de diferentes tipos de datos donde pueden residir diferentes tipos de datos y cada uno obtiene su propio bloque de memoria

usualmente utilizamos la unión cuando estamos seguros de que solo una de las variables se utilizará a la vez y desea la plena utilización de la memoria actual porque obtiene solo un bloque de memoria que es igual al tipo más grande.

 struct emp { char x;//1 byte float y; //4 byte } e; 

memoria total es obtener => 5 byte

 union emp { char x;//1 byte float y; //4 byte } e; 

memoria total es = 4 byte

¿Cuál es la diferencia entre estructura y unión?

La respuesta abreviada es: la deferencia está en la asignación de memoria. Explicación: en la estructura, se creará espacio de memoria para todos los miembros dentro de la estructura. En la memoria sindical, el espacio se creará solo para un miembro que necesite el mayor espacio de memoria. Considera el siguiente código:

 struct s_tag { int a; long int b; } x; union u_tag { int a; long int b; } y; 

Aquí hay dos miembros dentro de struct y union: int y long int. El espacio de memoria para int es: 4 bytes y el espacio de memoria para int largo es: 8 en sistema operativo de 32 bits.

Por lo tanto, para struct 4 + 8 = se crearán 12 bytes, mientras que se crearán 8 bytes para la unión

Ejemplo de código:

 #include struct s_tag { int a; long int b; } x; union u_tag { int a; long int b; } y; int main() { printf("Memory allocation for structure = %d", sizeof(x)); printf("\nMemory allocation for union = %d", sizeof(y)); return 0; } 

Ref: http://www.codingpractise.com/home/c-programming/structure-and-union/

Los sindicatos son útiles al escribir una función de orden de bytes que se detalla a continuación. No es posible con las estructuras.

 int main(int argc, char **argv) { union { short s; char c[sizeof(short)]; } un; un.s = 0x0102; if (sizeof(short) == 2) { if (un.c[0] == 1 && un.c[1] == 2) printf("big-endian\n"); else if (un.c[0] == 2 && un.c[1] == 1) printf("little-endian\n"); else printf("unknown\n"); } else printf("sizeof(short) = %d\n", sizeof(short)); exit(0); } // Program from Unix Network Programming Vol. 1 by Stevens. 

Una Unión es diferente de una estructura como una Unión se repite sobre las otras: redefine la misma memoria mientras que la estructura define una después de la otra sin superposiciones o redefiniciones.