Ferramentas do usuário

Ferramentas do site


Action disabled: source
prog2:unioes

Uniões

Uma união (union) é um tipo especial de estrutura (struct) no qual todos os campos internos iniciam na mesma posição da memória. Em outras palavras, os campos internos são sobrepostos e ocupam as mesmas posições de memória, como indica a figura a seguir:

Union vs. Struct

Uniões são uma forma eficiente de armazenar valores de diferentes tipos em uma mesma posição de memória. A quantidade de memória ocupada por uma união corresponde ao tamanho de seu maior campo.

Exemplo de união que permite “enxergar” os bytes individuais de um inteiro sem necessidade de operações de bits ou aritmética de ponteiros:

union.c
#include <stdio.h>
 
// guarda um inteiro OU um vetor de 4 bytes
typedef union
{
  int value ;
  unsigned char byte[sizeof(int)] ;
} intParts ;
 
int main ()
{
  intParts a ;
  int i ;
 
  a.value = 653459 ;
  for (i=0; i< sizeof(int); i++)
    printf ("%02x ", a.byte[i]) ;
  printf ("\n") ;
 
  return 0 ;
}

Uniões podem ser usadas para armazenar valores de diversos tipos em uma única locação de memória. Por exemplo, a união a seguir pode ser usada para armazenar números de diversos tipos:

typedef union
{
  short  shortVal ;
  int    intVal ;
  long   longVal ;
  float  floatVal ;
  double doubleVal ;
} numericValue ;

Entretanto, como saber qual o tipo do último valor armazenado, ou seja, qual o valor corrente?

Se armazenarmos um int e tentarmos ler um float teremos um valor errado, pois os valores são lidos byte a byte diretamente da área de memória da união, sem conversões.

union2.c
#include <stdio.h>
 
typedef union
{
  short  shortVal ;
  int    intVal ;
  long   longVal ;
  float  floatVal ;
  double doubleVal ;
} numericValue ;
 
int main ()
{
  numericValue a ;
 
  a.shortVal = 741 ;
  printf ("short : %d\n\n", a.shortVal) ;
 
  a.floatVal = 327.5432 ;
  printf ("float : %f\n", a.floatVal) ;
  printf ("short : %d\n\n", a.shortVal) ;
 
  a.doubleVal = 327.5432 ;
  printf ("double: %lf\n", a.doubleVal) ;
  printf ("float : %f\n", a.floatVal) ;
  printf ("short : %d\n", a.shortVal) ;
  return 0 ;
}

Para resolver esse problema pode ser usado um struct contendo a união e uma variável que indique o tipo do último valor armazenado:

typedef struct
{
  char type ;
  union                    // ATTENTION: "anonymous" union
  {
    short  shortVal ;
    int    intVal ;
    long   longVal ;
    float  floatVal ;
    double doubleVal ;
  } ;
} numericValue ;
 
numericValue a ;
 
a.intVal = 345 ;
a.type = 'i' ;
 
...
 
a.doubleVal = 3.141592653589793 ;
a.type = 'd' ;

O exemplo acima traz uma união anônima, ou seja, sem nome. Nesse caso, os membros da união são considerados como membros do struct externo que contém a união. Structs também podem ser anônimos.

Um outro uso interessante de união, no qual as moedas podem ser acessadas com nomes individuais ou como elementos de um vetor:

typedef union {
  struct
  {
    int quarter;
    int dime;
    int nickel;
    int penny;
  };
  int coins[4];
} Coins ;
 
Coins a ;
 
// equivalent operations!
a.dime = 34 ;
a.coins[1] = 34 ;

Exercícios

  1. Utilizando uma única variável union, crie uma função que receba um inteiro e calcule seu quadrado, em seguida, receba um caractere e, caso maiúsculo, imprima minúsculo, caso minúsculo, imprima maiúsculo, e por último, receba uma string de no máximo 8 caracteres e imprima seu inverso.
  2. Variáveis de 32 bits do tipo int podem representar valores entre −2,147,483,647 e +2,147,483,647, enquanto variáveis de 32 bits do tipo unsigned int podem representar valores entre 0 e +4,294,967,295. Crie um programa que receba um valor negativo do tipo int e mostre qual o valor resultante da conversão para o tipo unsigned int.
  3. Utilizando unions, crie um programa capaz de receber um determinado valor e calcular o módulo de 256 desse valor (dica: utilize char[sizeof(int)]).
prog2/unioes.txt · Última modificação: 2019/11/06 13:13 por maziero