Question

Understanding typedef Function Pointers in C

ccpppointerstypedef

Question

I am learning how to dynamically load DLLs, but I do not understand this line of C code:

typedef void (*FunctionFunc)();

I have a few questions about it:

  • Why is typedef used here?
  • The syntax looks unusual. After void, should there be a function name? It almost looks like an anonymous function.
  • Is this creating a function pointer that stores the memory address of a function?

I am confused about what this declaration means and how it works. Can someone clarify it?

Short Answer

By the end of this page, you will understand how function pointers work in C, why typedef is often used to simplify them, and how a declaration like typedef void (*FunctionFunc)(); creates a reusable type for pointing to functions. You will also see how this is useful when working with dynamically loaded DLL functions.

Concept

In C, a function pointer is a variable that can store the address of a function. This lets your program call a function indirectly.

That is especially useful when:

  • passing functions to other functions
  • selecting behavior at runtime
  • working with callbacks
  • loading functions from shared libraries or DLLs

The line:

typedef void (*FunctionFunc)();

means:

  • FunctionFunc is a type name
  • that type is a pointer to a function
  • the function returns void
  • the function takes an unspecified argument list in old-style C syntax

A clearer modern version is often:

typedef void (*FunctionFunc)(void);

This means: FunctionFunc is a type for "pointer to a function taking no arguments and returning nothing."

Why typedef is used

Without typedef, function pointer declarations are hard to read. typedef gives that complicated type a simple name.

Without typedef:

void (*func)();

With typedef:

typedef void (*FunctionFunc)(void);
FunctionFunc func;

This is easier to read and reuse.

Why the syntax looks strange

Function pointer syntax follows C's declaration rules. The parentheses matter.

void (*FunctionFunc)();

The *FunctionFunc part says FunctionFunc is a pointer. The () part says it points to a function.

If you wrote this instead:

void *FunctionFunc();

that would mean something completely different: a function named FunctionFunc that returns void *.

So the parentheses are what make it a pointer to a function, rather than a function returning a pointer.

Does it store a function address?

Yes. A function pointer stores the address of a function, so you can call that function through the pointer.

Example:

#include <stdio.h>

void sayHello(void) {
    printf("Hello\n");
}

int main(void) {
    void (*func)(void) = sayHello;
    func();
    return 0;
}

Here, func stores the address of sayHello, and func() calls it.

Why this matters with DLLs

When you load a DLL dynamically, you often get a function's address at runtime. You then store that address in a function pointer with the correct signature.

That lets you call the DLL function safely and clearly.

Mental Model

Think of a function pointer like a remote control with one programmed button.

  • The actual function lives somewhere in memory.
  • The function pointer does not contain the function itself.
  • It contains the location of that function.
  • When you use the pointer, you are saying: "go to that location and run that function."

Now think of typedef as a label maker.

Instead of repeatedly writing a complicated type like:

void (*)(void)

you give it a simple label:

FunctionFunc

So typedef does not create a function or a pointer variable by itself. It just creates a simpler name for a type.

Take Quiz

Syntax and Examples

Basic syntax

A normal function declaration:

void greet(void);

A function pointer variable that can point to that kind of function:

void (*funcPtr)(void);

A typedef for that function pointer type:

typedef void (*FunctionFunc)(void);

A variable using that typedef:

FunctionFunc funcPtr;

Example 1: Assign and call a function pointer

#include <stdio.h>

void greet(void) {
    printf("Hello from greet()\n");
}

int main(void) {
    typedef void (*FunctionFunc)(void);

    FunctionFunc func = greet;
    func();

    return 0;
}

What this does

  • greet is a function returning void
  • FunctionFunc is a type for pointers to functions with the same signature
  • func = greet; stores the function's address
  • func(); calls greet

Example 2: Without typedef

#include <stdio.h>

void greet(void) {
    printf("Hi\n");
}

int main(void) {
    void (*func)(void) = greet;
    func();
    return 0;
}

This works the same way, but many programmers prefer typedef when the type is used repeatedly.

Example 3: Dynamic loading style

typedef int (*AddFunc)(int, int);

This means AddFunc is a type for pointers to functions that:

  • take two int arguments
  • return an int

You could then use it like this:

AddFunc add;

Step by Step Execution

Consider this example:

#include <stdio.h>

typedef void (*FunctionFunc)(void);

void showMessage(void) {
    printf("Message shown\n");
}

int main(void) {
    FunctionFunc func = showMessage;
    func();
    return 0;
}

Step-by-step

1. Define a function pointer type

typedef void (*FunctionFunc)(void);

This creates a new type name, FunctionFunc.

That type means: pointer to a function that:

  • takes no arguments
  • returns void

2. Define a real function

void showMessage(void) {
    printf("Message shown\n");
}

This is an ordinary function.

3. Create a variable of that type

FunctionFunc func = showMessage;
  • func is a function pointer variable
  • it stores the address of showMessage

You can also write:

FunctionFunc func = &showMessage;

Both forms are commonly accepted for function pointers in C.

4. Call through the pointer

func();

This runs showMessage.

You may also see:

(*func)();

That also works. Both forms call the function through the pointer.

5. Program ends

return 0;

The output is:

Message shown

Real World Use Cases

Function pointers are common in real C programs.

1. Dynamically loaded libraries and DLLs

When you load a DLL at runtime, you often get a raw function address from the system API. You cast or assign that address to a function pointer type and then call it.

Example use case:

  • load a plugin
  • find a function like initialize
  • store it in a function pointer
  • call it

2. Callbacks

Many C libraries ask you to provide a function they can call later.

Examples:

  • sorting functions
  • event handlers
  • signal handlers
  • GUI callbacks

3. Strategy selection

A program may choose one of several functions depending on configuration or user input.

For example:

  • choose a compression algorithm
  • choose a parser
  • choose a logging function

4. Embedded systems

Function pointers are often used to connect hardware behavior to different handlers.

Examples:

  • interrupt handlers
  • device drivers
  • command dispatch tables

5. State machines and command tables

Programs can store function pointers in arrays or structs to map commands to actions.

Example:

  • command start points to startHandler
  • command stop points to stopHandler
Take Quiz

Real Codebase Usage

In real codebases, developers often use function pointer typedefs to make APIs easier to read and maintain.

Common patterns

1. Clear reusable type aliases

Instead of repeating complex declarations, teams define a named type once.

typedef void (*LogHandler)(const char *message);

This improves readability in structs and function parameters.

2. Validation after dynamic lookup

When loading a function from a DLL, developers usually check that the lookup succeeded before calling it.

if (func == NULL) {
    return -1;
}

This is a guard clause that prevents crashes.

3. Storing callbacks in structs

typedef void (*OnEvent)(int code);

typedef struct {
    OnEvent onStart;
    OnEvent onStop;
} Handlers;

This keeps related behavior together.

4. Dispatch tables

typedef void (*CommandFn)(void);

CommandFn commands[3];

This pattern is used for menu systems, interpreters, and protocol handlers.

5. Error handling around external functions

When a function comes from a DLL or plugin, code often validates:

  • the library loaded successfully
  • the function was found
  • the signature matches the expected type

If the signature is wrong, the program may compile but behave incorrectly at runtime.

Why typedef helps in teams

In a large project, this:

void (*)(void)

is much harder to understand than this:

FunctionFunc

Good type names communicate intent.

Common Mistakes

1. Forgetting the parentheses around *name

Broken code:

void *func(void);

This is not a pointer to a function returning void. It is a function returning void *.

Correct code:

void (*func)(void);

2. Using () when you really mean no arguments

This declaration:

typedef void (*FunctionFunc)();

uses old-style syntax meaning the parameters are not specified.

For beginners, this is safer and clearer:

typedef void (*FunctionFunc)(void);

That explicitly means no arguments.

3. Assigning a function with the wrong signature

Broken code:

int add(int a, int b) {
    return a + b;
}

typedef void (*FunctionFunc)(void);
FunctionFunc func = add;

This is the wrong type. The return type and parameters do not match.

Correct version:

typedef int (*AddFunc)(int, int);
AddFunc func = add;

4. Thinking typedef creates a variable

Broken thinking:

typedef void (*FunctionFunc)(void);

This does not create a pointer variable called FunctionFunc.

It creates a type name.

To create a variable:

FunctionFunc func;

5. Calling a NULL function pointer

Broken code:

FunctionFunc func = NULL;
func();

This will crash or cause undefined behavior.

Safer version:

if (func != NULL) {
    func();
}

6. Forgetting that dynamic loading requires the exact signature

If the real DLL function expects different parameters or a different calling convention, using the wrong type can lead to serious bugs.

Always match:

  • return type
  • parameter types
  • parameter count
  • calling convention, if applicable

Comparisons

Function pointer declaration vs typedef alias

StyleExampleMeaningReadability
Direct declarationvoid (*func)(void);func is a pointer to a functionHarder to read
With typedeftypedef void (*FunctionFunc)(void);FunctionFunc is a type aliasEasier to reuse

() vs (void) in C

SyntaxMeaningRecommendation
()Parameters not specifiedAvoid in modern beginner code
(void)Takes no argumentsPrefer this when there are no parameters

Function name vs function pointer

ItemExampleWhat it is
Functionvoid greet(void)Actual code that runs
Function pointer variablevoid (*func)(void)Stores the address of a compatible function
Typedef aliastypedef void (*GreetFunc)(void)A reusable name for that pointer type

Normal variable pointer vs function pointer

TypeExamplePoints to
Data pointerint *pData in memory
Function pointervoid (*f)(void)Executable function code

func() vs (*func)()

FormValid?Notes
func()YesCommon and readable
(*func)()YesMakes the pointer dereference explicit
Take Quiz

Cheat Sheet

Quick reference

Function pointer syntax

return_type (*pointer_name)(parameter_types);

Example:

int (*op)(int, int);

Typedef for function pointer

typedef return_type (*TypeName)(parameter_types);

Example:

typedef void (*FunctionFunc)(void);

Declare a variable using the typedef

FunctionFunc func;

Assign a function

func = showMessage;

or

func = &showMessage;

Call through the pointer

func();

or

(*func)();

Rules to remember

  • typedef creates a type alias, not a variable.
  • Parentheses around *name are required.
  • Use (void) for no parameters in modern C.
  • The function signature must match exactly.
  • Check for NULL before calling dynamically loaded functions.

Common pattern for DLL functions

typedef int (*AddFunc)(int, int);
AddFunc add = NULL;

Easy reading tip

Read this declaration from the inside out:

typedef void (*FunctionFunc)(void);
  • FunctionFunc
  • is * a pointer
  • to a function (void)
  • returning void

FAQ

Why does C function pointer syntax look so strange?

C declarations are designed to resemble usage. Parentheses are needed to show that the name is a pointer to a function, not a function returning a pointer.

Does typedef void (*FunctionFunc)(); create a function?

No. It creates a type alias named FunctionFunc.

Is FunctionFunc a variable name?

No. After typedef, the name becomes a type name. You would create variables later using that type.

What is the difference between () and (void) in C?

() means the parameter list is not specified. (void) explicitly means no arguments. (void) is usually the better choice.

Can a function pointer hold any function?

No. It should only point to functions with a compatible signature.

Why are function pointers useful for DLLs?

When a DLL function is found at runtime, you receive its address. A function pointer lets you store that address and call the function.

Do I need to use &functionName when assigning a function pointer?

Usually no. In most cases, functionName works because the function name converts to a pointer automatically.

Can I store function pointers in arrays or structs?

Yes. This is very common in dispatch tables, callback systems, and plugin architectures.

Take Quiz

Mini Project

Description

Build a small C program that uses a function pointer typedef to choose and call different operations. This demonstrates the same core idea used when calling functions loaded from a DLL: you store a function address in a variable and call it through that variable.

Goal

Create a program that stores function addresses in function pointer variables and calls the selected function correctly.

Requirements

  1. Define a function pointer type with typedef.
  2. Create at least two functions with the same signature.
  3. Store one of those functions in a function pointer variable.
  4. Call the function through the pointer.
  5. Show that the pointer can be reassigned to a different function.
Take Quiz

Keep learning

Related questions

View more