Diferenças
Aqui você vê as diferenças entre duas revisões dessa página.
| Ambos lados da revisão anterior Revisão anterior | |||
| c:unioes [2023/08/15 11:57] – maziero | c:unioes [2023/08/15 11:57] (atual) – maziero | ||
|---|---|---|---|
| Linha 1: | Linha 1: | ||
| + | ====== Uniões ====== | ||
| + | |||
| + | {{ progc_unions.mkv |Video desta aula}} | ||
| + | |||
| + | Uma **união** ('' | ||
| + | |||
| + | A figura a seguir ilustra a diferença entre '' | ||
| + | |||
| + | {{ union-struct.png |Union vs. Struct}} | ||
| + | |||
| + | Uniões são uma forma eficiente de armazenar valores de diferentes tipos em uma mesma posição de memória. Obviamente, somente um valor pode ser armazenado a cada instante. A quantidade de memória ocupada por uma união corresponde ao tamanho de seu **maior campo**. | ||
| + | |||
| + | No exemplo abaixo, uma união permite " | ||
| + | |||
| + | <code c union.c> | ||
| + | #include < | ||
| + | |||
| + | // 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 ; | ||
| + | |||
| + | printf ("%d: ", a.value) ; | ||
| + | | ||
| + | for (i = 0; i < sizeof (int); i++) | ||
| + | printf ("%02x ", a.byte[i]) ; | ||
| + | printf (" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Os campos '' | ||
| + | |||
| + | ^ // | ||
| + | | '' | ||
| + | | '' | ||
| + | |||
| + | 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: | ||
| + | |||
| + | <code c> | ||
| + | typedef union | ||
| + | { | ||
| + | short shortVal ; | ||
| + | int intVal ; | ||
| + | long | ||
| + | float floatVal ; | ||
| + | double doubleVal ; | ||
| + | } numeric_t ; | ||
| + | </ | ||
| + | |||
| + | Entretanto, como saber qual o tipo do último valor armazenado, ou seja, qual o valor corrente? | ||
| + | |||
| + | <note warning> | ||
| + | Se armazenarmos um '' | ||
| + | </ | ||
| + | |||
| + | <code c union-error.c> | ||
| + | #include < | ||
| + | |||
| + | typedef union | ||
| + | { | ||
| + | short shortVal ; | ||
| + | int intVal ; | ||
| + | long | ||
| + | float floatVal ; | ||
| + | double doubleVal ; | ||
| + | } numeric_t ; | ||
| + | |||
| + | int main () | ||
| + | { | ||
| + | numeric_t a ; | ||
| + | |||
| + | a.shortVal = 741 ; | ||
| + | printf (" | ||
| + | printf (" | ||
| + | |||
| + | a.floatVal = 327.5432 ; | ||
| + | printf (" | ||
| + | printf (" | ||
| + | |||
| + | a.doubleVal = 327.5432 ; | ||
| + | printf (" | ||
| + | printf (" | ||
| + | printf (" | ||
| + | return 0 ; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Para resolver esse problema pode ser usada uma estrutura contendo a união e uma variável que indique o tipo do último valor armazenado: | ||
| + | |||
| + | <code c union-type.c> | ||
| + | #include < | ||
| + | |||
| + | typedef struct | ||
| + | { | ||
| + | union // ATTENTION: " | ||
| + | { | ||
| + | short shortVal ; | ||
| + | int intVal ; | ||
| + | long | ||
| + | float floatVal ; | ||
| + | double doubleVal ; | ||
| + | } ; | ||
| + | enum { SHORT, INT, LONG, FLOAT, DOUBLE } type ; | ||
| + | } numeric_t ; | ||
| + | |||
| + | // imprime tipo numérico | ||
| + | void print_num (numeric_t n) | ||
| + | { | ||
| + | switch (n.type) | ||
| + | { | ||
| + | case SHORT : printf (" | ||
| + | case INT : printf (" | ||
| + | case LONG : printf (" | ||
| + | case FLOAT : printf (" | ||
| + | case DOUBLE : printf (" | ||
| + | default | ||
| + | } | ||
| + | } | ||
| + | |||
| + | int main () | ||
| + | { | ||
| + | numeric_t a ; | ||
| + | |||
| + | a.shortVal = 119 ; | ||
| + | a.type = SHORT ; | ||
| + | print_num (a) ; | ||
| + | printf (" | ||
| + | |||
| + | a.longVal = 3451212796756 ; | ||
| + | a.type = LONG ; | ||
| + | print_num (a) ; | ||
| + | printf (" | ||
| + | |||
| + | a.doubleVal = 3.141592653589793 ; | ||
| + | a.type = DOUBLE ; | ||
| + | print_num (a) ; | ||
| + | printf (" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <note tip> | ||
| + | O exemplo acima traz um exemplo de **união anônima**, ou seja, sem nome. Nesse caso, os membros da união são considerados como membros da estrutura externa que contém a união. Estruturas também podem ser anônimas. | ||
| + | </ | ||
| + | |||
| + | A linguagem C respeita a ordem de declaração dos campos de uma estrutura, ou seja, eles são colocados na memória na mesma ordem em que são declarados. | ||
| + | |||
| + | Isso permite outro exemplo interessante do uso de uma união, no qual as moedas podem ser acessadas com nomes individuais ou como elementos de um vetor: | ||
| + | |||
| + | <code c> | ||
| + | typedef union { | ||
| + | struct | ||
| + | { | ||
| + | int quarter; | ||
| + | int dime; | ||
| + | int nickel; | ||
| + | int penny; | ||
| + | }; | ||
| + | int coins[4]; | ||
| + | } Coins_t ; | ||
| + | |||
| + | Coins_t a ; | ||
| + | |||
| + | a.dime = 34 ; // são operações equivalentes | ||
| + | a.coins[1] = 34 ; | ||
| + | </ | ||
| + | |||
| + | Outro exemplo interessante é a definição de números reais segundo o padrão [[https:// | ||
| + | |||
| + | <code c> | ||
| + | // extraído (e simplificado) de / | ||
| + | |||
| + | union ieee754_float | ||
| + | { | ||
| + | float f; | ||
| + | |||
| + | /* This is the IEEE 754 single-precision format. | ||
| + | struct | ||
| + | { | ||
| + | #if __BYTE_ORDER == __BIG_ENDIAN | ||
| + | unsigned int negative:1; | ||
| + | unsigned int exponent:8; | ||
| + | unsigned int mantissa: | ||
| + | # | ||
| + | #if __BYTE_ORDER == __LITTLE_ENDIAN | ||
| + | unsigned int mantissa: | ||
| + | unsigned int exponent:8; | ||
| + | unsigned int negative:1; | ||
| + | # | ||
| + | } ieee; | ||
| + | }; | ||
| + | </ | ||
| + | |||
| + | ===== Exercícios ===== | ||
| + | |||
| + | - Utilizando uma única variável '' | ||
| + | - Variáveis de 32 bits do tipo '' | ||
| + | - Utilizando unions, crie um programa capaz de receber um determinado valor e calcular o módulo de 256 desse valor (dica: utilize '' | ||