Question
While learning to dynamically load DLLs, I encountered this declaration:
typedef void (*FunctionFunc)();
What does this declaration mean?
- Why is
typedefused here? - Why is there no function name immediately after
void? - Does this create a function pointer that can store the memory address of a function?
Please clarify the syntax and how it is used when loading functions from a DLL.
Short Answer
By the end of this page, you will understand how to read a function-pointer declaration, why typedef gives it a reusable name, and how such pointers are used to call functions loaded from a DLL at runtime.
Concept
typedef void (*FunctionFunc)(); creates a type alias named FunctionFunc.
That alias means:
“A pointer to a function that takes no arguments and returns
void.”
It does not create a function and it does not create a function-pointer variable by itself. It only defines a convenient name for that type.
typedef void (*FunctionFunc)();
Read it from the identifier outward:
FunctionFuncis inside(* ... ), so it is a pointer.()means that pointer points to a function with no parameters.voidat the beginning means that function returns no value.typedefsays that this whole declaration defines a type name rather than a variable.
After the alias exists, you can declare an actual variable:
FunctionFunc functionPointer = nullptr;
That variable can later hold the address of a compatible function.
Function pointers matter when behavior is selected at runtime. Dynamic DLL loading is one example: a program can load a library, look up an exported function by name, store its address in a function pointer, and call it without linking to that library at build time.
Mental Model
Think of a function as a machine in a workshop. Its address tells you where that machine is located.
A function pointer is a labelled note that can hold the location of a compatible machine. Before using the note, you must know what kind of machine it refers to:
- What inputs does it accept?
- What output does it produce?
FunctionFunc is the label for one kind of note:
“This note points to a machine that accepts no input and produces no returned value.”
typedef is like creating that short label so you do not need to write the full, complicated description every time.
Syntax and Examples
The direct syntax for declaring a pointer to a function is:
return_type (*pointer_name)(parameter_types);
For a function that takes no parameters and returns void:
void (*functionPointer)();
The parentheses around *functionPointer are essential. They say that functionPointer is a pointer to a function.
Naming the type with typedef
typedef void (*FunctionFunc)();
Now FunctionFunc can be used like a normal type name:
FunctionFunc functionPointer = nullptr;
Assigning and calling a function
#include <iostream>
void sayHello()
{
std::cout << "Hello\n";
}
typedef void (*FunctionFunc)();
int main()
{
FunctionFunc functionPointer = &sayHello;
functionPointer(); // Calls sayHello
(*functionPointer)(); // Also calls sayHello
}
Both call forms are valid. In C and C++, calling through functionPointer() is usually clearer.
The declaration is not an anonymous function. void is the function's return type. The function pointer's name is FunctionFunc in the typedef declaration, and functionPointer in the variable declaration.
Step by Step Execution
Consider this program:
#include <iostream>
void start()
{
std::cout << "Starting...\n";
}
typedef void (*FunctionFunc)();
int main()
{
FunctionFunc action = &start;
action();
}
Execution proceeds as follows:
-
startis defined. It is a function with this signature:void start(); -
typedef void (*FunctionFunc)();definesFunctionFuncas a type meaning “pointer to avoid()function.” No memory is allocated for a pointer at this point. -
FunctionFunc action = &start;creates the variableaction. -
&startis the address of thestartfunction. Becausestarthas the compatible signaturevoid(), its address can be stored inaction. -
action();follows the stored address and executesstart. -
startwritesStarting...and returns no value because its return type isvoid.
Real World Use Cases
Function pointers are useful whenever code needs to choose or receive behavior dynamically.
- Dynamically loaded DLLs: Load a DLL at runtime and retrieve exported function addresses with
GetProcAddresson Windows. - Callbacks: Give a library a function to call later, such as an event handler or comparison function.
- C APIs: Many C libraries accept function pointers for logging, memory allocation, parsing, and error handling.
- Plugin systems: A host program can load optional modules and call known exported entry points.
- Table-driven behavior: A command number or state can select one of several functions from an array of function pointers.
For example, the C standard library sorting function qsort receives a comparison function pointer so it can sort many kinds of data.
Real Codebase Usage
In real code, developers typically give function-pointer types meaningful names and validate them before calling them.
Dynamic DLL loading on Windows
#include <windows.h>
#include <iostream>
using FunctionFunc = void (*)();
int main()
{
HMODULE library = LoadLibraryA("plugin.dll");
if (library == nullptr)
{
std::cerr << "Could not load plugin.dll\n";
return 1;
}
auto rawAddress = GetProcAddress(library, "RunPlugin");
if (rawAddress == nullptr)
{
std::cerr << "RunPlugin was not found\n";
FreeLibrary(library);
return 1;
}
auto runPlugin = reinterpret_cast<FunctionFunc>(rawAddress);
runPlugin();
FreeLibrary(library);
}
Important real-project practices:
- Use a clear alias such as
RunPluginFnorFunctionFunc. - Check that the library loaded successfully.
- Check that the symbol lookup succeeded before calling it.
- Keep the DLL loaded for as long as any pointer into it may be called.
- Ensure the return type, parameters, and calling convention exactly match the exported function.
Modern C++ often uses using instead of typedef because it is easier to read:
using FunctionFunc = void (*)();
It defines the same type as the original typedef form.
Common Mistakes
Forgetting parentheses
This does not declare a function pointer:
void *functionPointer();
It declares a function named functionPointer that takes no arguments and returns void*.
Use parentheses around the *:
void (*functionPointer)();
Treating typedef as a variable declaration
typedef void (*FunctionFunc)();
This does not allocate storage for a pointer. Declare a variable separately:
FunctionFunc callback = nullptr;
Using an incompatible function signature
int returnsNumber()
{
return 42;
}
using FunctionFunc = void (*)();
FunctionFunc callback = &returnsNumber; // Error: incompatible type
The return type and parameter types must match.
Calling a null pointer
FunctionFunc callback = nullptr;
callback(); // Undefined behavior; likely crashes
Check that a pointer was obtained before calling it:
if (callback != nullptr)
{
callback();
}
Ignoring the calling convention in Windows DLL code
Some Windows APIs and DLL exports use a calling convention such as __stdcall. A mismatch can corrupt the call stack, especially in 32-bit builds.
using FunctionFunc = void (__stdcall *)();
The declaration must match the DLL function exactly. Prefer a shared header supplied by the DLL when one is available.
Unloading a DLL too early
A pointer returned by GetProcAddress points into the loaded DLL. Do not call it after FreeLibrary has unloaded that DLL.
Comparisons
| Declaration | Meaning |
|---|---|
void run(); | A function named run that returns void. |
void (*runPointer)(); | A variable that points to a function returning void. |
typedef void (*FunctionFunc)(); | An alias for the type “pointer to a function returning void.” |
FunctionFunc runPointer; | A function-pointer variable using the alias. |
using FunctionFunc = void (*)(); | Modern C++ spelling of the same type alias. |
typedef versus using
| Feature | typedef | using |
|---|---|---|
| Available in C | Yes | No |
| Available in C++ | Yes | Yes |
| Function pointer alias | typedef void (*Fn)(); | using Fn = void (*)(); |
| Typical modern C++ preference | Supported | Usually preferred for readability |
Function pointers versus std::function
| Feature | Function pointer | std::function |
|---|---|---|
| Can point to | Ordinary compatible functions | Functions, lambdas, functors, bound calls |
| Overhead | Usually minimal | May have additional overhead |
| DLL lookup use | Common and appropriate | Usually not the direct result type |
| Header | None required | <functional> |
For direct DLL exports, a raw function pointer is the normal representation because the DLL provides a machine-level function address with a specific signature.
Cheat Sheet
// Direct declaration
void (*callback)();
// Type alias: C and C++
typedef void (*FunctionFunc)();
// Type alias: modern C++
using FunctionFunc = void (*)();
// Declare a variable
FunctionFunc callback = nullptr;
// Store a compatible function address
void work();
callback = &work;
// Call it
callback();
voidbefore(*name)is the return type.()contains the parameter list; empty means no parameters in C++.- Parentheses around
*nameare required. typedef/usingcreates a type alias, not an object.- Match return type, parameter types, and calling convention exactly.
- Check for
nullptrbefore calling a dynamically obtained function pointer. - Do not use a DLL function pointer after unloading its DLL.
FAQ
What does typedef void (*FunctionFunc)(); mean?
It defines FunctionFunc as a type alias for a pointer to a function that takes no arguments and returns void.
Does typedef create a function pointer variable?
No. It creates only a type name. Write FunctionFunc fn = nullptr; to create a variable.
Why is the asterisk inside parentheses?
Without parentheses, C and C++ parse the declaration as a function returning a pointer. (*name) changes the meaning to a pointer to a function.
Is void (*)() an anonymous function?
No. It is a type description. void is the return type, * indicates a pointer, and () describes the function parameters.
Can I assign any function to FunctionFunc?
No. The function must have a compatible signature: no parameters and a void return type. Its calling convention must also match when applicable.
Should I use typedef or using in C++?
Both work. In modern C++, using FunctionFunc = void (*)(); is often easier to read. Use typedef when writing C-compatible declarations or following an existing codebase style.
Why check GetProcAddress before calling the result?
If the DLL does not export that name, GetProcAddress returns nullptr. Calling a null function pointer is invalid and can crash the program.
Why does a DLL function pointer become invalid after FreeLibrary?
The pointer refers to code inside that DLL. Once the DLL is unloaded, that code may no longer be present in memory.
Mini Project
Description
Build a small callback-based task runner. It stores the address of a no-argument function in a typedef-defined function pointer, validates the pointer, and then runs the selected task. This mirrors the final step of calling a function obtained from a DLL.
Goal
Create and call a void() function pointer through a reusable typedef alias.
Requirements
Requirement 1
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.