Nested Functions in C
Nesting of functions refers to placing the definition of the function inside another functions. In C programming, nested functions are not allowed. We can only define a function globally.
Example:
#include <stdio.h>
int main() {
void fun(){
printf("GeeksForGeeks");
}
fun();
return 0;
}
Output
main.c:4:15: error: function definition is not allowed here
4 | void fun(){
| ^
main.c:7:5: error: use of undeclared identifier 'fun'
7 | fun();
| ^
The above code gives error because defining a function inside another function is not possible in C programming language.
GCC Extension for Nested Function
GCC compiler provides feature of nesting functions as an extension even though it is not the part of standard C.
Example:
#include <stdio.h>
int main() {
printf("Outer Function\n");
// Defining inner function
void inner() {
printf("Inner Function\n");
}
// Calling nested functions
inner();
return 0;
}
Output
Outer Function Inner Function
If you want to declare the function before its definition, then use auto keyword.
// Declaring inner function
auto void inner();
Nested Function Scope and Lifetime
The scope of nested function is limited to the outer function in which it is declared. Only the outer function can call the nested function directly. But if we pass the pointer of the nested function to some other function, then we can call it even outside the enclosing function. It is because GCC uses the concept of trampoline to implement nested functions.
Trampolines are the small piece of code generated at runtime when the nested functions are called outside their scope. When the address of a nested function is taken, a trampoline is created, and its address is returned which contain two information:
- The real address of nested function code.
- The address of enclosing function stack frame.
Due to this, the nested function can also access the variables from the enclosing function. It is called lexical scoping.
Example:
#include <stdio.h>
void print(void (*fp)()) {
fp();
}
void outer(int x) {
int y = 10;
void inner() {
printf("%d\n", x + y);
}
// Creating pointer to inner()
void (*fp)() = &inner;
// Passing fp pointer to other function
print(fp);
}
int main() {
// Calling enclosing function
outer(5);
return 0;
}
Output
15
The above program defines a nested function inner() inside outer() that adds two numbers x and y (local variables of outer) and prints the result. When it creates a pointer to inner(), a trampoline is created and passed to the function print(), which then calls inner() to display the sum. It was successfully able to determine the sum of x and y in the function print() even though these variables being outside its immediate scope.
Lifetime
The nested function, like any other function, exists in the code as long as the program runs, but its ability to work properly depends on whether the outer function’s stack frame is present or not. So, it can be said that its effective lifetime is till the stack frame of enclosing function exists.
For example, the below program results in error:
#include <stdio.h>
void (*outer(int x))() {
int y = 10;
void inner() {
printf("%d\n", x + y);
}
// Return the address of inner
return &inner;
}
int main() {
// Get function pointer from outer
void (*fp)() = outer(5);
// Call the nested function via pointer
fp();
return 0;
}
Output
segmentation fault
This is because when we call the function inner() through function pointer fp, the stack frame of outer() is already destroyed. If we do not access the variables of enclosing function, even this program can run without errors.
//Driver Code Starts
#include <stdio.h>
void (*outer(int x))() {
int y = 10;
//Driver Code Ends
void inner() {
// Not accessing outer()'s variables
printf("Hello from inner()");
}
//Driver Code Starts
return &inner;
}
int main() {
void (*fp)() = outer(5);
fp();
return 0;
}
//Driver Code Ends
Output
Hello from inner()