Introduction
You've heard of an int
and a string
, but have you heard of a void (*(*[])())()
?
Yes, this is a real type declaration in C, and we'll see just how to use it and how to deal with complicated types.
Program Memory
One of the C language's superpowers is its low-level memory management.
You've likely manipulated memory before. Most languages allow you to pass variables by reference (i.e. its memory address) as well as by value (i.e. a copy is made so that there are no side effects).
C gives developers a standard low-level interface to program memory on both the heap and the stack.
An important part of this interface is pointer types.
Pointers
Put simply, a pointer is a variable that stores a memory address to another variable.
Since a pointer is a variable, we can have a pointer to a pointer. And a pointer to a pointer to a pointer. And so on, and forever. See this diagram for reference:
The void (*(*[])())()
"What?"
Using the awesome converter at cdecl.org, we can see what this type declaration really means.
Let's work backwards to understand what's going on.
Breakdown
foo -- foo
foo[] -- is an array
*foo[] -- of pointers
(*foo[])() -- to functions
*(*foo[])() -- returning pointers
(*(*foo[])())() -- to functions
void (*(*foo[])())(); -- returning void
Now that we understand the individual components, let's create it!
Function returning Void
A function that doesn't return anything (i.e. a procedure) is a void function.
For this, we'll define a function that prints "Apple!".
void apple() {
printf("Apple!\n");
}
Pointer to a Function returning Void
This is simple. It's a pointer to the function that we just declared.
&apple;
Function returning a Pointer to a Function returning Void
We need a function that returns &apple
. The hard part here is the type signature.
void (*pointer_to_apple())() {
return &apple;
}
One mistake I made initially was declaring this as void *pointer_to_apple()
. This would be incorrectly returning a Pointer to Void
, as opposed to a Pointer to a Function returning Void
.
You may wish to look at the syntax of Function Pointers in order to understand this better.
Pointer to a Function returning a Pointer to a Function returning Void
This is simple again. It's a pointer to this new function.
&pointer_to_apple;
Array of Pointers to Functions returning a Pointer to a Function returning Void
The final step, and an easy one at that. Pretending we defined two similar sets of functions and pointers, we can an array of these new pointers.
{
&pointer_to_apple,
&pointer_to_banana,
&pointer_to_cherry
};
Let's define a variable with this array.
Our variable foo is an array of of type void (*(*[])())()
with a size of 3.
void (*(*foo[3])())() = {
&pointer_to_apple,
&pointer_to_banana,
&pointer_to_cherry
};
Using this Array
We can now iterate through the array to print our various fruits.
The only boilerplate here is getting the size of a void (*(*[])())()
. This is standard for iterating through arrays in C, as using the sizeof operator to determine the size of arrays is error prone.
size_t n = sizeof(foo)/sizeof(foo[0]);
We can now iterate through the array. As each element is effectively a pointer to a function returning a pointer to a function, we use foo[i]()()
, which calls each function pointed to.
for (int i = 0; i < n; ++i) {
foo[i]()();
}
Let's check the output.
>>> Apple!
>>> Banana!
>>> Cherry!
>>>
>>> Process finished with exit code 0
Success!
Example Code
You can check this code out in my GitHub repository.
#include <stdio.h>
void apple() {
printf("Apple!\n");
}
void banana() {
printf("Banana!\n");
}
void cherry() {
printf("Cherry!\n");
}
void (*pointer_to_apple())() {
printf("Getting pointer to apple.\n");
return &apple;
}
void (*pointer_to_banana())() {
printf("Getting pointer to banana.\n");
return &banana;
}
void (*pointer_to_cherry())() {
printf("Getting pointer to cherry.\n");
return &cherry;
}
int main() {
void (*(*foo[3])())() = {
&pointer_to_apple,
&pointer_to_banana,
&pointer_to_cherry
};
size_t n = sizeof(foo) / sizeof(foo[0]);
for (int i = 0; i < n; ++i) {
foo[i]()();
}
return 0;
}
Hey, guys! Thank you for reading. I hope that you enjoyed this.
Keep up to date with me:
- DEV: https://dev.to/tao/
- Twitter: https://twitter.com/LloydTao
- GitHub: https://github.com/LloydTao
- LinkedIn: https://www.linkedin.com/in/LloydTao/
Catch you around!
Top comments (1)