2011-01-20 6 views

Respuesta

11

Puede usar cualquier tipo de datos en una unión, no hay ninguna restricción.

En cuanto al uso de uniones sobre estructuras, las estructuras presentan sus datos secuencialmente en la memoria. Esto significa que todos sus subcomponentes están separados.

Los sindicatos, por otro lado, utilizan la misma memoria para todos sus subcomponentes, por lo que solo puede existir uno a la vez.

Por ejemplo: se utilizan

        +-----+-----+ 
struct { int a; float b } gives | a | b | 
           +-----+-----+ 
            ^ ^
            |  | 
       memory location: 150 154 
            | 
            V 
           +-----+ 
union { int a; float b } gives | a | 
           | b | 
           +-----+ 

estructuras en las que un "objeto" se compone de otros objetos, como un objeto de punto consta de dos números enteros, los que están siendo la x e y las coordenadas:

typedef struct { 
    int x;   // x and y are separate 
    int y; 
} tPoint; 

Las uniones se usan generalmente en situaciones en las que un objeto puede ser una de muchas cosas, pero solo una a la vez, como un sistema de almacenamiento sin tipo:

typedef enum { STR, INT } tType; 
typedef struct { 
    tType typ;   // typ is separate. 
    union { 
     int ival;  // ival and sval occupy same memory. 
     char *sval; 
    } 
} tVal; 

Son útiles para guardar memoria, aunque eso tiende a ser cada vez menos importante en la actualidad (aparte del trabajo de bajo nivel, como los sistemas integrados) por lo que no se ve mucho.

+0

Las uniones no son para guardar memoria: expresan un * tipo de suma *, es decir. un tipo que contiene, por ejemplo. * cualquiera * un flotante * o * un int. Los sindicatos son difíciles de usar y bastante limitados. Por favor considere usar 'boost :: variant' en su lugar. –

+11

Me temo que tengo que estar en desacuerdo con casi todo eso, @Alexandre :-) Ellos _son_ (incluso ahora) útiles para salvar la memoria, especialmente en el mundo pequeño integrado. No son difíciles de usar si comprendes el diseño subyacente (incluidas las debilidades definidas por la implementación) y hasta que alguien aumente los puertos a C (verifica las etiquetas), el tipo de variante no va a ser de mucha utilidad :-) – paxdiablo

+0

Me olvidé 1) que era C 2) que las personas necesitan estar cerca del hardware a veces. Sin embargo, mi punto es que las uniones (en C++) no deberían usarse para representar tipos de suma. –

4

Bueno, de acuerdo con la norma ISO/IEC 9899: TC3 (el estándar C99):

Un tipo de unión se describe un conjunto no vacío superposición de objetos miembro, cada uno de que tiene un nombre opcionalmente especificado y posiblemente distinta tipo.

En resumen, el espacio de memoria de los miembros de la unión se superpone, y los nombres que le da a los miembros de la unión le permiten leer la memoria en esa ubicación de tamaño. Considere:

#include <stdio.h> 
#include <stdint.h> 

typedef union 
{ 
    struct 
    { 
     uint8_t a; 
     uint8_t b; 
     uint8_t c; 
     uint8_t d; 
    }; 
    uint32_t x; 
} somenewtype; 

typedef union 
{ 
    uint32_t* p; 
    uint8_t* q; 
} somepointer; 

int main(int argc, char** argv) 
{ 
    uint32_t r; 
    uint8_t s; 
    somenewtype z; 
    somepointer p; 
    r = 0x11223344; s = 0x11; 
    z.x = 0x11223344; 
    p.p = &r; 
    p.q = &s; 
    printf("%x%x%x%x\n", z.d, z.c, z.b, z.a); 
    printf("%x %x\n", *(p.p), *(p.q)); 
} 

En el primer printf, lo que estamos haciendo es imprimir las piezas de 8 bits del entero de 32 bits. Esperando, por supuesto, que no haya relleno en esa estructura anónima.

En la segunda impresión? Tenía que pasar por el uso de GDB de entender, pero lo hice:

p.p = (uint32_t *) 0x7fffffffde5c; 
p.q = (uint8_t *) 0x7fffffffde5b "\021D3\"\021P\337\377\377\377\177"; 
p.p = (uint32_t *) 0x7fffffffde5b; 

Bueno, por supuesto, los punteros son todos del mismo tamaño, por lo que la asignación de p.q sobrescribe la dirección de p.p. Sospecho que la desreferenciación de la dirección del entero de 32 bits a un puntero de 8 bits es la impresión de "lo que sea en esa ubicación + 32 bits de tamaño" que, casualmente, para mí es 22334411. Pero sospecho que, en ese momento, el comportamiento no está definido.

De todos modos, el punto de que era pequeño ejercicio para demostrar que:

  • uniones se pueden utilizar para acceder a la misma posición de memoria a través de un modificador de "tipo" diferente.
  • Tiene que tener cuidado con lo que hace y comprender el tipo subyacente que está utilizando. Si va a usar punteros, tenga cuidado con sus modificaciones ya que podría comenzar a señalar quién sabe qué.

Debo señalar que puedo ver el uso práctico para somenewtype pero no para somepointer - que fue un ejemplo artificioso que estaba bastante seguro de que se rompa.

Cuestiones relacionadas