Skip to content

Latest commit

 

History

History
388 lines (302 loc) · 7.95 KB

File metadata and controls

388 lines (302 loc) · 7.95 KB

Unions

Table of Contents

Overview

  • Stores different types of data in the same storage area.
  • Saves on space for alternating data types.
  • Size determined by the largest type.

Defining a union

The declaration is identical to that of a struct, except the keyword union is used.

union union_tag { // union_tag optional
    type1 identifier_1;
    type2 identifier_2;
} optional_variable_definitions;

The union definition is placed in the header and included in all source files that use the union type.

Example

union Data {
    int i; // 4 bytes
    float f; // 8 bytes
    char str[20]; // 20 bytes
} data1, data2; //global union variables optional

A variable of type Data, can store an integer or a float, or a string of chars, not all. A struct could store all but not a union.

The memory occupied by a union will be large enough to hold the largest member, in this case 20 bytes as char str[20] is the largest member.

  • No memory is allocated until variables are created.
  • There is no limit to the number of members.
  • Struct can contain unions, as can arrays.
  • Pointers to unions work the same as with structs.

Example

#include <stdio.h>

union Car {
    int i_value; // 4 bytes
    float f_value; // 4 bytes
    char c_value[40]; // 40 bytes largest member
    }; //car1, car2, *car3; // can declare here

int main()
{
    union Car car1, car2, *car3; // declare unions
    printf("Size of union: %zu bytes.\n", sizeof(car1));
    return 0;
}

Output

Size of union: 40 bytes.

The example code below, shows how the union memory storage is changed when assigning different type to the members.

#include <stdio.h>
#include <string.h>

union sample {
    int i;
    char ca[4];
    float f;
};

int main()
{

    union sample u;
    
    u.i = 42;
    printf("%08x %f %s\n", u.i, u.f, u.ca);
    
    strcpy(u.ca, "Abc"); // copy 3 chars leaving space for null operator
    printf("%08x %f %s\n", u.i, u.f, u.ca);
    
    u.f = 1.0/3.0;
    printf("%08x %f %s\n", u.i, u.f, u.ca);

	return 0;
}

Output

0000002a 0.000000 * // 2a hex is 42
00636241 0.000000 Abc // 00 is null operator, 63 is `A`, 62 is `b`, 41 is 'c'.
3eaaaaab 0.333333 □□□>0□□□ // 32aaaaab is 0.3333 in hex

Anonymous unions

Introduced in C11. Anonymous unions exist only inside another union or struct. It has no union tag or variables assigned to it.

Example

#include <stdio.h>

struct Owner{
    char socsecurity[12];
};

struct Lease_company{
    char name[40];
    char headquarters[40];
};

struct Car_data {
    char make[15];
    int status;
    union { // Anonymous union
        struct Owner own_car;
        struct Lease_company lease_car;
    };
};

int main()
{
    ...
struct {
    char* name;
    enum symbolType type;
    union {
        int i;
        float f;
        char c;
    }; data; // union variable 
} table [entries]; // array named table

Unions with typedef

As with a struct a typedef can be declared for a union. This is not best practice as the word union is good information for the reader of your code.

typedef union {
    int x;
    float y;
    char z;
} myunion;

int main(){

    myunion u; // no need for union keyword
    u.x = 99;
    u.y = 1.0;
    u.z = 'c';

    ...
}

Accessing union members

We access/assign data to members of a union, the same was we do with a struct:

  • with the (.) dot operator to access members
  • with the (->) indirection operator to access pointer variables

Union member assignment example

#include <stdio.h>

union {
    int code;
    float cost;
} item; // global variable

int main()
{
    item.code = 1234;

    return 0;
}

Accessing pointer members example

#include <stdio.h>

union {
    int code;
    float cost;
} item, *ptrst;

int main()
{
    ptrst = &item;
    ptrst->code = 9876; // assigns an int to code member

    return 0;
}

The following expressions are equivalents

  • ptrst->code = 9876; // preferred method
  • item.code = 9876;
  • (*ptrst).code = 9876;
#include <stdio.h>

union mixed {
    char c;
    float f;
    int i;
};

int main()
{
    union mixed x; // can store one only at a time of the three members
    x.c = 'q';
    printf("Char at c: %c\n", x.c); // prints, Char at c: q
    x.f = 3.142; // union memory overwritten with 3.142
    printf("Float at f: %f\n", x.f); // prints, Float at f: 3.142000
    x.i = 1234 / 2; // union memory overwritten with 617
    printf("Int at i: %d\n", x.i); // prints, Int at i: 617
    return 0;
}

Union initialisation

As with a struct there are a few ways to initialise a union.

#include <stdio.h>

union Number {
    int x;
    double y;
};

int main()
{

    union Number value1 = {12}; // int is first member in union, so needs a int

    // preferred alternatives
    union Number value2 = {.x = 12}; 
    
    union Number value3 = {.y = 3.142};

    union Number value4;
    value4.x = 12;

    union Number value5;
    value5.y = 3.142;

    return 0;
}

Using pointers example

#include <stdio.h>

union Number {
    int x;
    double y;
};


int main()
{

    union Number value1;
    union Number *value2 = &value1;

    value2->y = 10.0;
    printf("Double at value2 y: %f\n", value2->y);

    return 0;
}

Using functions example

#include <stdio.h>

union Number {
    int x;
    double y;
};

// Initialise another union of Number via function foo
void foo(union Number n){
    union Number value2 = n;
    printf("Double at value2 y: %f\n", value2.y);
}

int main()
{

    union Number value1 = {.y = 12.2};
    printf("Double at value1 y: %f\n", value1.y);

    foo(value1); // initialise another union with a union via a function

    return 0;
}

Printing union members

Here is a program that uses a struct and a anonymous union. The struct represents a Spaceship and the union represents a upgrade speed multiplier.

#include <stdio.h>
#include <stdbool.h>

struct Spaceship {
    char* name;
    bool upgrade;
    char upgradeClass;
    float speed;
    union {
        float aClassUpgrade;
        float sClassUpgrade;
    };
};

void print_stats(struct Spaceship* c){
    printf("Name: %s: ", c->name);
    if (c->upgrade){
        if (c->upgradeClass == 's')
            printf("speed %f", c->speed * c->sClassUpgrade);
        else 
            printf("speed %f", c->speed * c->aClassUpgrade);
    } else {
        printf("speed %f", c->speed);
    }
    printf("\n");
}


int main()
{

    struct Spaceship cruiserX;
    cruiserX.name = "Cruiser X";
    cruiserX.speed = 23.0;
    cruiserX.upgrade = true;
    cruiserX.upgradeClass = 's';
    cruiserX.sClassUpgrade = 2.5;
    
    print_stats(&cruiserX);

    struct Spaceship traderY;
    traderY.name = "Trader Y";
    traderY.speed = 12.0;
    traderY.upgrade = true;
    traderY.upgradeClass = 'a';
    traderY.aClassUpgrade = 1.1;

    print_stats(&traderY);

    return 0;
}

Output

Name: Cruiser X: speed 57.500000
Name: Trader Y: speed 13.200001

External References