We know that the main() function is the entry point of a program. This is generally true. But we can execute some functions even before main() starts.
In some circumstances, you might need to execute an user defined function before main(). For example, if you are creating a library, you might need to initialize certain data structures before any function of your library is called. You can certainly define an initialize() function. But the user of that library would have to remember to call this function. Better solution would be to execute initializing function during library load, even before the main() starts.
Similarly, you’ll need some function for clean up after main() returns.
Using __attribute__ ((constructor)) / ((destructor))
GNU C compiler has a feature to mark functions that would be executed before or after the main() function.
- We can use __attribute__ ((constructor)) to mark a function constructor.
- We can use __attribute__ ((destructor)) to mark a function as destructor.
The constructor functions will be executed before main() and the destructors after main().
The Program
#include<stdio.h>
void FunBeforeMain(void) __attribute__ ((constructor));
void FunAfterMain(void) __attribute__ ((destructor));
void FunBeforeMain(void)
{
printf("FunBeforeMain() called.\n");
}
void FunAfterMain(void)
{
printf("FunAfterMain called.\n");
}
int main(void)
{
printf("main() started.\n");
printf("main() exited.\n");
return 0;
}
We marked “FunBeforeMain()” with __attribute__ ((constructor)) and “FunAfterMain()” with __attribute__ ((destructor)).
Here is the output of the program.
From this output, we can see that the “FunBeforeMain()” is executed before main() starts and “FunAfterMain()” after main() returns.
The special sections, .ctors and .dtors of ELF (Executable and Linkable Format), contain the function references marked with constructor and destructor attributes. When the program (binary or shared library) gets loaded, the program loader checks whether any function reference is present in .ctors section. If so, called those functions. Similar thing happens when the program is unloaded. Function references present in .dtor section are called after main() exits.
We can mark multiple functions as constructor or destructor.
#include<stdio.h>
void FunBeforeMain1(void) __attribute__ ((constructor));
void FunBeforeMain2(void) __attribute__ ((constructor));
void FunAfterMain1(void) __attribute__ ((destructor));
void FunAfterMain2(void) __attribute__ ((destructor));
void FunBeforeMain1(void)
{
printf("FunBeforeMain1() called.\n");
}
void FunBeforeMain2(void)
{
printf("FunBeforeMain2() called.\n");
}
void FunAfterMain1(void)
{
printf("FunAfterMain1 called.\n");
}
void FunAfterMain2(void)
{
printf("FunAfterMain2 called.\n");
}
int main(void)
{
printf("main() started.\n");
printf("main() exited.\n");
return 0;
}
Output of the above program.
One thing to notice in this output is that the destructors are called in reverse order.
In C++ we can use other mechanisms to call function before main().