Code of the Day
IntermediateStructs and enums

typedef idioms

Simplify C type names with typedef — the typedef struct pattern, function pointer typedefs, and when typedef helps versus hinders readability.

CIntermediate9 min read
Recommended first
By the end of this lesson you will be able to:
  • 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 — now NodePtr p looks 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.

Finished reading? Mark it complete to track your progress.

On this page