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
typedefused 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:
FunctionFuncis 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.
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
greetis a function returningvoidFunctionFuncis a type for pointers to functions with the same signaturefunc = greet;stores the function's addressfunc();callsgreet
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
intarguments - 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;
funcis 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
startpoints tostartHandler - command
stoppoints tostopHandler
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
| Style | Example | Meaning | Readability |
|---|---|---|---|
| Direct declaration | void (*func)(void); | func is a pointer to a function | Harder to read |
| With typedef | typedef void (*FunctionFunc)(void); | FunctionFunc is a type alias | Easier to reuse |
() vs (void) in C
| Syntax | Meaning | Recommendation |
|---|---|---|
() | Parameters not specified | Avoid in modern beginner code |
(void) | Takes no arguments | Prefer this when there are no parameters |
Function name vs function pointer
| Item | Example | What it is |
|---|---|---|
| Function | void greet(void) | Actual code that runs |
| Function pointer variable | void (*func)(void) | Stores the address of a compatible function |
| Typedef alias | typedef void (*GreetFunc)(void) | A reusable name for that pointer type |
Normal variable pointer vs function pointer
| Type | Example | Points to |
|---|---|---|
| Data pointer | int *p | Data in memory |
| Function pointer | void (*f)(void) | Executable function code |
func() vs (*func)()
| Form | Valid? | Notes |
|---|---|---|
func() | Yes | Common and readable |
(*func)() | Yes | Makes the pointer dereference explicit |
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
typedefcreates a type alias, not a variable.- Parentheses around
*nameare required. - Use
(void)for no parameters in modern C. - The function signature must match exactly.
- Check for
NULLbefore 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.
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
- Define a function pointer type with
typedef. - Create at least two functions with the same signature.
- Store one of those functions in a function pointer variable.
- Call the function through the pointer.
- Show that the pointer can be reassigned to a different function.
Keep learning
Related questions
2D Array Loop Order and Cache Performance in C
Learn why swapping nested loops changes 2D array performance in C, using row-major memory layout, cache locality, and practical benchmarks.
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.