Question

Difference Between struct and union in C

cstructunions

Question

In C, what is a good way to understand the difference between a struct and a union?

I understand that a struct stores enough memory for all of its members, while a union uses only enough memory for its largest member. Beyond that memory layout difference, are there any other important differences, such as operating system-level behavior?

For example, how should I think about these two declarations?

struct ExampleStruct {
    int id;
    float price;
    char code;
};

union ExampleUnion {
    int id;
    float price;
    char code;
};

Short Answer

By the end of this page, you will understand how struct and union differ in C, especially in memory layout, data access, and practical use. You will also learn that this is mainly a language and memory-model concept, not an operating system feature.

Concept

A struct and a union are both user-defined types in C, but they represent data in very different ways.

struct

A struct gives each member its own storage. All fields can hold valid values at the same time.

struct Point {
    int x;
    int y;
};

If you set x and y, both values are stored independently.

union

A union makes all members share the same memory location. Only one member's value is meaningfully stored at a time.

union Number {
    int i;
    float f;
};

If you write to i and then write to f, the f write reuses the same bytes and overwrites the previous contents.

Why this matters

This difference affects:

  • Memory usage: union can save space.
  • Meaning of data: with a union, the same bytes can be interpreted in different ways.
  • Program design: struct is for objects with multiple fields; union is for one value that may have different forms.

Is there an OS-level difference?

Usually, no. This is primarily a C language and compiler memory layout concept, not an operating system feature.

The compiler decides layout rules such as:

  • member offsets in a struct
  • size of a union
  • alignment and padding

The operating system generally does not treat struct and union differently. They are just blocks of memory in your program. What matters is how the C language defines access to that memory.

Mental Model

Think of a struct as a desk with separate labeled drawers:

  • one drawer for id
  • one drawer for price
  • one drawer for code

Each member has its own space, so all values can exist together.

Think of a union as a single drawer with several labels stuck on it:

  • id
  • price
  • code

There is still only one drawer. The labels are different ways to interpret the same space. If you put something in as id and later put something in as price, the new value replaces the old bytes.

So:

  • struct = many storage locations grouped together
  • union = one storage location viewed in different ways
Take Quiz

Syntax and Examples

Basic syntax

struct Person {
    int age;
    char initial;
};

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

Example: struct

#include <stdio.h>

struct Person {
    int age;
    char initial;
};

int main(void) {
    struct Person p;
    p.age = 25;
    p.initial = 'A';

    printf("age = %d\n", p.age);
    printf("initial = %c\n", p.initial);
    return 0;
}

Here both fields keep their values because each member has separate storage.

Example: union

#include <stdio.h>

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

int main(void) {
    union Value v;

    v.i = 42;
    printf("i = %d\n", v.i);

    v.f = 3.14f;
    printf("f = %.2f\n", v.f);

    return 0;
}

When v.f is assigned, it reuses the same memory previously used by v.i. That means the old integer value is no longer the active value.

Size example

#include <stdio.h>

struct ExampleStruct {
    int id;
    float price;
    char code;
};

union ExampleUnion {
    int id;
    float price;
    char code;
};

int main(void) {
    printf("struct size: %zu\n", sizeof(struct ExampleStruct));
    printf("union size: %zu\n", sizeof(union ExampleUnion));
    return 0;
}

The exact sizes may vary because of padding and alignment, but:

  • the struct is large enough for all members
  • the union is large enough for its largest member

Step by Step Execution

Consider this union example:

#include <stdio.h>

union Data {
    int i;
    char c;
};

int main(void) {
    union Data d;

    d.i = 65;
    printf("d.i = %d\n", d.i);

    d.c = 'B';
    printf("d.c = %c\n", d.c);

    return 0;
}

Step by step

  1. union Data d;

    • Memory is reserved for one union Data variable.
    • Its size is enough for the largest member.
  2. d.i = 65;

    • The shared memory is filled with the integer representation of 65.
    • At this point, i is the active member.
  3. printf("d.i = %d\n", d.i);

    • Prints 65.
  4. d.c = 'B';

    • The same shared memory is written again, now as a char.
    • The previous integer bytes are no longer reliably meaningful as an int value.
    • Now c is the active member.
  5. printf("d.c = %c\n", d.c);

    • Prints B.

Compare with a struct

#include <stdio.h>

struct Data {
    int i;
    char c;
};

int main(void) {
    struct Data d;

    d.i = 65;
    d.c = 'B';

    printf("d.i = %d\n", d.i);
    printf("d.c = %c\n", d.c);
    return 0;
}

Here both values remain stored, because i and c have separate memory.

Real World Use Cases

When struct is used

struct is used far more often than union in everyday C programming.

Common uses:

  • storing records such as users, points, products, or configuration data
  • grouping related fields into one object
  • representing packets, headers, or state objects
  • passing multiple related values to functions

Example:

struct User {
    int id;
    char role;
    float rating;
};

A user has all of these properties at the same time, so struct is the correct choice.

When union is used

union is useful when a value can be one of several types, but never all at once.

Common uses:

  • memory-constrained systems
  • parsers handling different token value types
  • message payloads where only one payload format is active
  • tagged data types combined with an enum

Example:

enum ValueType {
    TYPE_INT,
    TYPE_FLOAT,
    TYPE_CHAR
};

struct TaggedValue {
    enum ValueType type;
    union {
        int i;
        float f;
        char c;
    } data;
};

This pattern lets a program store one value at a time while tracking which member is valid.

Take Quiz

Real Codebase Usage

In real projects, developers usually use union together with a tag that tells the program which member is currently valid.

Tagged union pattern

enum EventType {
    EVENT_KEY,
    EVENT_MOUSE
};

struct Event {
    enum EventType type;
    union {
        int key_code;
        struct {
            int x;
            int y;
        } mouse;
    } data;
};

This is common in:

  • event systems
  • compilers and interpreters
  • protocol handling
  • embedded firmware

Why the tag matters

Without a tag, code can easily read the wrong union member.

struct usage patterns in real code

Developers use struct for:

  • configuration objects
  • return values with multiple fields
  • state containers
  • linked list and tree nodes
  • API request and response models

Guarding access to unions

A common pattern is:

  • validate the tag first
  • read only the matching union field
  • use switch or if to branch safely
switch (value.type) {
    case TYPE_INT:
        printf("%d\n", value.data.i);
        break;
    case TYPE_FLOAT:
        printf("%f\n", value.data.f);
        break;
    case TYPE_CHAR:
        printf("%c\n", value.data.c);
        break;
}

This makes union-based code safer and easier to understand.

Common Mistakes

1. Thinking a union stores all members at once

Broken assumption:

union Data {
    int i;
    float f;
};

union Data d;
d.i = 10;
d.f = 2.5f;
printf("%d\n", d.i);  // Not a safe way to expect the old int value

Why it is wrong:

  • assigning d.f overwrites the shared memory
  • d.i is no longer the active value

2. Using a union when a struct is needed

Broken design:

union Person {
    int age;
    char initial;
};

If a person needs both age and initial, use a struct, not a union.

3. Ignoring padding and alignment

Beginners often assume sizes are just the sum of member sizes.

struct Example {
    char c;
    int i;
};

This may be larger than 1 + 4 because of alignment rules.

4. Reading a union member without tracking what was written

Problem:

union Value v;
v.i = 100;
printf("%f\n", v.f);  // Interpreting int bytes as float bytes

Even if this compiles, it is usually not what you want.

5. Assuming there is an OS-specific behavior difference

struct and union are mostly about:

  • language rules
  • compiler layout
  • CPU alignment needs

They are not special operating-system objects.

How to avoid mistakes

  • Use struct when all fields should exist together.
  • Use union when only one representation is active at a time.
  • Pair unions with an enum tag.
  • Check sizeof(...) when memory layout matters.
  • Be careful with low-level byte interpretation.

Comparisons

Featurestructunion
Memory for membersSeparate memory for each memberShared memory for all members
Total sizeUsually enough for all members plus paddingEnough for largest member plus alignment
Can all members hold values at once?YesNo, only one meaningful active member at a time
Typical useRecords and grouped dataVariant data and memory saving
Safer for beginnersYesLess so
Common in application codeVery commonMore specialized

struct vs union in one sentence

  • Use a struct for has-a set of fields.
  • Use a union for is-one-of-several-forms.

Example comparison

struct Coordinates {
    int x;
    int y;
};

A point has both x and y.

union InputValue {
    int whole_number;
    float decimal_number;
};

This value is either an int or a float at one time.

Take Quiz

Cheat Sheet

struct S {
    int a;
    float b;
};

union U {
    int a;
    float b;
};
  • struct: each member has its own storage
  • union: all members share the same storage
  • struct size: enough for all members + padding
  • union size: enough for largest member + alignment
  • struct: all fields can be used together
  • union: only one member should be treated as active
  • No special OS-level difference in normal C usage
  • Layout details depend on compiler, target, and alignment rules

Good rule of thumb

  • Need multiple fields at once? Use struct.
  • Need one value that may take different forms? Use union.

Safer union pattern

enum Kind { INT_KIND, FLOAT_KIND };

struct Value {
    enum Kind kind;
    union {
        int i;
        float f;
    } data;
};

Useful operators

sizeof(struct S)
sizeof(union U)

Edge case reminder

Reading a different union member than the one most recently written can be confusing and must be done carefully.

FAQ

Is a union just a smaller struct?

No. A union is not just a space-optimized struct. Its members share the same memory, which changes how values are stored and read.

When should I use a struct instead of a union?

Use a struct when all fields are part of the object at the same time, such as a user with an id, name, and age.

When is a union useful in C?

A union is useful when a value can be one of several types, such as a token in a parser or an event payload in a system.

Does the operating system treat structs and unions differently?

Usually no. This is mainly a C language and compiler memory layout issue, not an OS-level distinction.

Why is a union often combined with an enum?

The enum acts as a tag so the program knows which union member currently contains valid data.

Can a union and struct have unexpected sizes?

Yes. Alignment and padding can change sizes, especially for structs. Always use sizeof instead of guessing.

Is reading one union member after writing another allowed?

It may compile, but it can be tricky and is often not the right design for beginners. Use a tagged union pattern when possible.

Take Quiz

Mini Project

Description

Build a small C program that stores different kinds of values using a tagged union. This demonstrates the practical difference between struct and union: the struct holds the type tag and the union holds one active value.

Goal

Create a program that can store and print either an integer, a float, or a character safely using an enum and a union.

Requirements

  • Define an enum to represent the active value type.
  • Define a struct that contains the enum tag and a union of possible values.
  • Create at least three example values: one integer, one float, and one character.
  • Write a function that prints the stored value based on the tag.
  • Compile and run the program to verify that each value is printed correctly.
Take Quiz

Keep learning

Related questions

View more