typedef idioms
Simplify C type names with typedef — the typedef struct pattern, function pointer typedefs, and when typedef helps versus hinders readability.
- Use typedef to create an alias for a struct type
- Apply the typedef struct pattern in one declaration
- Create a typedef for a function pointer type
- Explain when typedef is helpful and when it obscures types
Writing struct Rectangle every time you declare a variable is repetitive. typedef lets you create an alias for any type — struct, pointer, function pointer, or primitive. It is one of C's most-used idioms for making code more readable.
Basic typedef
typedef unsigned long long uint64;
uint64 big_number = 18446744073709551615ULL;typedef existing_type new_name; introduces new_name as an alias for existing_type. This is purely a compile-time name substitution — it does not create a new type.
typedef struct — the main idiom
The most common pattern:
typedef struct {
double x;
double y;
} Point;
/* Now use Point instead of struct Point */
Point origin = {0.0, 0.0};
Point p = {.x = 3.0, .y = 4.0};Or with separate tag and typedef (necessary for self-referential structs):
typedef struct Node {
int data;
struct Node *next; /* must use struct Node here, not Node */
} Node;The struct tag (struct Node) and the typedef name (Node) can be the same. Inside the struct body, Node is not yet defined (the typedef comes after), so self-referential pointers must use the struct Node form.
Complete example
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[32];
int age;
float salary;
} Employee;
Employee *create_employee(const char *name, int age, float salary) {
Employee *e = malloc(sizeof(Employee));
if (!e) { return NULL; }
snprintf(e->name, sizeof(e->name), "%s", name);
e->age = age;
e->salary = salary;
return e;
}
void print_employee(const Employee *e) {
printf("%-20s age %2d salary $%.2f\n", e->name, e->age, e->salary);
}
int main(void) {
Employee *alice = create_employee("Alice", 30, 95000.0f);
Employee *bob = create_employee("Bob", 25, 78000.0f);
print_employee(alice);
print_employee(bob);
free(alice);
free(bob);
return 0;
}typedef for function pointers
Function pointer syntax in C is notoriously difficult to read. typedef helps:
/* Without typedef: confusing */
int (*compare)(const void *, const void *);
/* With typedef: readable */
typedef int (*Comparator)(const void *, const void *);
Comparator cmp = my_compare_function;This is especially useful when passing or returning function pointers:
typedef void (*Callback)(int event_code, void *data);
void register_handler(int event, Callback cb) {
/* store cb for later invocation */
}When typedef helps and when it hinders
Use typedef when:
- Spelling the full type every time is genuinely painful (
struct LinkedListNode). - The abstraction is stable and the underlying type is irrelevant to the caller (e.g.
size_t). - You are creating a public API and may want to change the underlying type later.
Avoid typedef when:
- It hides that something is a pointer.
typedef struct Node *NodePtr— nowNodePtr plooks like a value but is a pointer. This leads to "hidden pointer" bugs that are hard to reason about. - It creates multiple aliases for the same type, adding cognitive overhead.
The Linux kernel style guide avoids typedef struct entirely — it considers it unnecessary indirection. The C standard library uses it extensively (FILE, size_t, uint32_t). Both are valid approaches; consistency within a codebase matters most.
uint8_t, uint32_t, int64_t are typedefs defined in <stdint.h>. They are the standard way to get exact-width integer types in portable C code. Always use them when the exact bit width matters (file formats, network protocols, hardware registers).
Where to go next
Next: enums and bit flags — representing a fixed set of named values with enum, and using bitwise OR to combine flags efficiently.
Pointers to structs
Work with pointers to structs in C — the arrow operator, dynamic struct allocation, self-referential structs for linked lists, and function parameters.
enum and bit flags
Represent named constants with enum and combine options efficiently with bitwise OR — the bit flags pattern used throughout C APIs and system headers.