typedef base_type custom_alias;
The above syntax creates custom_alias as an exact equivalent of base_type, which can then be used anywhere base_type is valid.
typedef unsigned char UCHAR;
UCHAR test_byte = 'x';
This example defines UCHAR as a shorthand for unsigned char, then uses it to declare a single-byte character variable.
Multiple aliases can be assigned to a single base type in one line:
typedef unsigned short u16, ushort_dim, tile_index;
Here, u16, ushort_dim, and tile_index all refer to unsigned short.
Typedef works with pointer types, though clarity should be prioritized:
typedef uint8_t* u8_ptr;
uint8_t buffer[128];
u8_ptr head = buffer;
In this snippet, u8_ptr replaces uint8_t* for declaring a buffer head pointer.
Array types can also be aliased to avoid repeating length specifications:
typedef short five_shorts[5];
five_shorts sensor_readings = {205, 198, 212, 201, 209};
five_shorts now represents an array of exactly 5 short integers.
For function pointers, typedef simplifies otherwise dense syntax:
typedef int (*boolish_func)(void);
This defines boolish_func as a pointer to a function that takes no arguments and returns an int (intended for 0/1 logical values here).
Key Advantages
Improved Readability
Aliases make variable purposes explicit at a glance:
typedef char* CSTR;
CSTR product_name;
CSTR error_log_path;
Using CSTR immediately signals these variables hold null-terminated C-style strings.
Simplified Access to Complex Custom Types
For structs, unions, and enums, typedef removes repetitive struct/union/enum keywords:
struct pixel_node {
uint8_t r, g, b, a;
struct pixel_node *next;
};
typedef struct pixel_node* PixelList;
Now PixelList can declare pointers to linked pixel nodes without repeating struct pixel_node*.
Typedef can also be combined directly with anonymous struct/union/enum definitions:
typedef struct {
uint8_t r, g, b, a;
} RGBA_Pixel;
Effortless Type Refactoring
Changing variable types across a codebase only requires modifying one typedef line:
// Initial type
typedef double score_t;
score_t midterm, final, quiz_avg;
Later, switch all scores to extended precision:
// Updated type applies to all score_t variables
typedef long double score_t;
Enhanced Portability
Type widths vary across CPU architectures. For example, a 32-bit integer constant like 100000 works on 32-bit systems but causes overflow on 16-bit ones. Standard library headers like stdint.h and stddef.h use typedef to define architecture-agnostic aliases:
#include <stdint.h>
int32_t safe_large_num = 100000;
size_t array_length = 64;
int32_t guarantees a 32-bit signed integer, while size_t adjusts to the system’s native pointer size for array indexing.
Simplified Complex Type Declarations
Consider this dense declaration:
char (*(*fetch_callbacks(void))[5])(void);
Breaking it down with typedef makes it readable:
typedef char (*char_returner)(void);
typedef char_returner callback_arr5[5];
callback_arr5 * fetch_callbacks(void);
Now it is clear:
char_returneris a pointer to a no-argument function returinngcharcallback_arr5is an array of 5char_returnerpointersfetch_callbacksis a no-arguement function returning a pointer tocallback_arr5