C provides several additional language features that improve code readability, simplify data type usage, and optimize memory usage. Three commonly used features are enum, typedef, and union. These features are widely used in both general software development and low-level embedded systems programming.
1. Enum in C
An enum (enumeration) is a user-defined data type used to assign meaningful names to integer constants. Enums make programs significantly easier to read and maintain by replacing magic numeric constants with descriptive names.
Enum Syntax
enum enum_name
{
VALUE1,
VALUE2,
VALUE3
};
Example Program
#include <stdio.h>
enum LedState // Define enum type
{
OFF, // Assigned 0 by default
ON // Assigned 1 automatically
};
int main()
{
enum LedState led = ON; // Declare and assign enum variable
printf("LED State Value: %d\n", led); // Prints underlying integer value
return 0;
}
Console Output
LED State Value: 1
How It Works
By default, the compiler assigns consecutive integer values to the enum members starting from 0. Here, OFF is assigned 0 and ON is assigned 1. Enums increase code readability significantly because descriptive names are much easier to understand than arbitrary numeric codes.
2. Typedef in C
The typedef keyword is used to establish a new alias name for an existing data type. It helps simplify complex declarations and guarantees portability across different hardware architectures.
Typedef Syntax
typedef existing_type new_alias_name;
Example Program
#include <stdio.h>
typedef unsigned int uint; // Define "uint" as an alias for "unsigned int"
int main()
{
uint value = 100; // Declare variable using the custom alias
printf("Value: %u\n", value);
return 0;
}
Console Output
Value: 100
How It Works
In this program, typedef creates the alias uint for unsigned int. The compiler treats uint exactly like the native unsigned int type, but using aliases keeps code clean, portable, and easy to maintain across different 8-bit, 16-bit, and 32-bit hardware architectures.
3. Union in C
A union is a custom data type where all member variables share the **exact same memory location**. Unlike structures (which allocate separate memory space for each member), a union's total allocated size is equal to the size of its largest member, meaning only one member can contain a valid value at any given instant.
Union Syntax
union union_name
{
data_type member1;
data_type member2;
};
Example Program
#include <stdio.h>
union Data // Members share the exact same 4-byte block in memory
{
int number; // 4 Bytes
float value; // 4 Bytes
};
int main()
{
union Data d;
// 1. Assign and print integer data
d.number = 10;
printf("Integer: %d\n", d.number);
// 2. Assign float data (Overwrites d.number)
d.value = 5.5;
printf("Float: %.1f\n", d.value);
// 3. Printing d.number now reads floating-point bits as an integer (corrupt data)
printf("Integer after overwrite: %d\n", d.number);
return 0;
}
Console Output
Integer: 10
Float: 5.5
Integer after overwrite: 1085276160
Union Shared Memory Layout
d.number = 10; // Stored as 0x0000000A in shared space
d.value = 5.5; // OVERWRITES exact same space with float representation (0x40B00000)
How It Works
All members of a union share the exact same physical storage space. When you write d.value = 5.5, the floating-point IEEE-754 bit pattern overwrites the previous value of d.number. Attempting to print d.number afterwards displays 1085276160 (the raw integer translation of those float bits). Unions are incredibly powerful tools for memory optimization in resource-constrained environments.
Important Points
Keep these critical rules in mind when using enums, typedefs, and unions in C:
- Enums: Enums define structured lists of readable integer constants. By default, values start at
0, but members can be assigned custom integer values explicitly. - Typedef:
typedefis purely a compiler directive that creates aliases for existing data types, does not allocate any new memory. - Unions: Union members share the same memory location. The size of a union is equal to the size of its largest member, unlike a structure, which holds all elements contiguously.
Concept Overview
A quick summary of the visual relationships between these advanced data type features:
Typedef → Creates a clean alias name for an existing data type
Union → Stores multiple variables overlapping inside the same memory space
Embedded Focus
These features are heavily relied upon in embedded systems programming to construct highly optimized, ultra-clear firmware layers:
// 1. Typedefs abstract away hardware register widths
typedef unsigned char uint8_t;
// 2. Enums organize hardware state machines cleanly
enum DeviceState
{
DEVICE_OFF,
DEVICE_ON,
DEVICE_ERROR
};
In firmware development, typedef abstracts variable widths across microcontrollers, enum eliminates mysterious magic numbers inside state machines, and union lets developers access 16-bit or 32-bit registers as raw bytes for SPI or UART packet transmissions without using manual memory pointers.