Question
Understanding __attribute__((constructor)) and __attribute__((destructor)) in C and C++
Question
In GCC-style code, what exactly does __attribute__((constructor)) do, and when does the annotated function run?
I want to understand several details:
- When exactly is a constructor function executed?
- Why does the syntax use two parentheses?
- Is
__attribute__a function, a macro, or a language extension? - Does this work in C, C++, or both?
- Does the function need to be declared
static? - When does
__attribute__((destructor))run?
For example, in Objective-C:
__attribute__((constructor))
static void initialize_navigationBarImages(void) {
navigationBarImages = [[NSMutableDictionary alloc] init];
}
__attribute__((destructor))
static void destroy_navigationBarImages(void) {
[navigationBarImages release];
}
Short Answer
By the end of this page, you will understand what GCC/Clang function attributes like constructor and destructor mean, when those functions run, why the syntax looks unusual, and how they are commonly used in C, C++, and Objective-C codebases. You will also learn the limitations, common pitfalls, and when normal initialization patterns are usually a better choice.
Concept
__attribute__((constructor)) and __attribute__((destructor)) are compiler-specific function attributes supported by compilers such as GCC and Clang.
They are used to mark functions that should run automatically:
- constructor: before
main()starts - destructor: after
main()ends or during program shutdown
These names can be confusing at first because they are not the same thing as C++ class constructors and destructors.
What __attribute__ is
__attribute__ is not a normal function call and not part of standard C syntax in the original language specification. It is a compiler extension that lets you attach extra information to declarations.
For example, you can attach attributes to:
- functions
- variables
- types
The compiler then changes how it treats that declaration.
When constructor functions run
A function marked with:
__attribute__((constructor))
is scheduled to run automatically before control enters main().
Typical timing:
Mental Model
Think of the program as a theater performance.
main()is the moment the play officially begins.- A
constructorfunction is the crew preparing the stage before the curtain opens. - A
destructorfunction is the crew cleaning up after the audience leaves.
You did not call these functions directly. The runtime and loader arrange for them to happen automatically.
Another way to think about it:
- normal functions are tasks you call yourself
- constructor/destructor functions are tasks you put on the program's automatic startup/shutdown checklist
That is convenient, but it also means the work happens somewhat "behind the scenes," so other developers may not immediately see why some state already exists before main() runs.
Syntax and Examples
The basic syntax looks like this:
__attribute__((constructor))
void setup(void) {
/* runs before main() */
}
__attribute__((destructor))
void cleanup(void) {
/* runs during shutdown */
}
Simple C example
#include <stdio.h>
__attribute__((constructor))
static void startup(void) {
printf("Startup function runs before main()\n");
}
__attribute__((destructor))
static void shutdown_cleanup(void) {
printf("Shutdown function runs after main()\n");
}
int main(void) {
printf("Inside main()\n");
return 0;
}
Expected output order is typically:
Startup function runs before main()
Inside main()
Shutdown function runs after main()
Step by Step Execution
Consider this example:
#include <stdio.h>
int global_value = 0;
__attribute__((constructor))
static void init_value(void) {
global_value = 42;
printf("constructor: global_value = %d\n", global_value);
}
__attribute__((destructor))
static void destroy_value(void) {
printf("destructor: global_value = %d\n", global_value);
}
int main(void) {
printf("main: global_value = %d\n", global_value);
return 0;
}
Step by step:
-
The program is loaded.
-
Before
main()starts, the runtime finds functions marked with theconstructorattribute. -
init_value()runs automatically. -
sets to .
Real World Use Cases
Here are common situations where constructor/destructor attributes are useful.
1. Library initialization
A shared library may need to initialize internal state when loaded.
Examples:
- set up lookup tables
- initialize mutexes
- register logging hooks
2. Plugin registration
A plugin can register itself automatically without requiring the main application to call a setup function manually.
__attribute__((constructor))
static void register_plugin(void) {
/* add plugin to registry */
}
3. Instrumentation and profiling
Low-level tooling may install tracing, counters, or diagnostics at startup and flush data at shutdown.
4. Resource setup and cleanup
Some systems initialize file descriptors, caches, or native handles early and release them at termination.
5. Objective-C runtime setup
In Objective-C projects, these attributes are sometimes used for early initialization logic in frameworks or app infrastructure code.
Even so, many app-level tasks are better placed in clearer lifecycle hooks when possible.
Real Codebase Usage
In real projects, developers usually use this feature for small, infrastructure-level setup, not for large application logic.
Common patterns
Internal registration
static void register_feature(void) __attribute__((constructor));
static void register_feature(void) {
/* insert feature into internal registry */
}
This is common in plugin systems and test frameworks.
Guarding setup code
Because startup code runs automatically, developers often add safety checks.
__attribute__((constructor))
static void init_cache(void) {
if (cache_already_initialized()) {
return;
}
build_cache();
}
Keeping visibility local
static is frequently added so the helper does not become part of the public API.
Small shutdown cleanup
__attribute__((destructor))
{
write_pending_logs();
}
Common Mistakes
Beginners often run into these problems.
1. Thinking this is a normal C function call
Broken idea:
__attribute__((constructor));
This does nothing by itself. The attribute must be attached to a declaration.
Correct:
__attribute__((constructor))
static void setup(void) {
}
2. Confusing it with C++ class constructors
This:
__attribute__((constructor))
void setup(void) {
}
is not the same as:
class User {
public:
User();
};
One is a compiler attribute on a function. The other is a language feature of C++ classes.
3. Assuming static is required
Broken assumption:
__attribute__((constructor))
void {
}
Comparisons
| Concept | What it is | When it runs | Portable? | Typical use |
|---|---|---|---|---|
__attribute__((constructor)) | Compiler attribute on a function | Before main() | Compiler-specific | Automatic startup setup |
__attribute__((destructor)) | Compiler attribute on a function | At shutdown | Compiler-specific | Automatic cleanup |
| Normal function call | Regular code you call directly | Wherever you call it | Yes | Clear explicit setup |
| C++ class constructor | Object initialization feature | When an object is created | Yes in C++ |
Cheat Sheet
__attribute__((constructor))
void setup(void);
__attribute__((destructor))
void cleanup(void);
__attribute__is a compiler extension, not a normal function.constructorfunction runs beforemain().destructorfunction runs during normal program shutdown.- Works in GCC/Clang-based C, C++, and Objective-C.
staticis optional.staticonly changes linkage/visibility.- This is not the same as a C++ class constructor/destructor.
- Nested parentheses exist because
__attribute__wraps a list of attributes.
Example:
#include <stdio.h>
__attribute__((constructor))
static void setup(void) {
printf("before main\n");
}
__attribute__((destructor))
static void {
();
}
FAQ
Does __attribute__((constructor)) run before main()?
Yes. Its purpose is to run the function automatically before main() starts.
Does __attribute__((destructor)) run after main()?
Yes, during normal program shutdown, typically after main() returns or exit() is called.
Is __attribute__ part of standard C?
No. It is a compiler extension commonly supported by GCC and Clang.
Can I use __attribute__((constructor)) in C++?
Yes, if your compiler supports GCC-style attributes. It is different from a C++ class constructor.
Why are there two parentheses in __attribute__((constructor))?
The outer parentheses belong to the attribute syntax, and the inner parentheses contain one or more attribute names or attribute arguments.
Does the function have to be static?
No. static is optional and only controls file-local visibility.
Is this safe for large application initialization?
Mini Project
Description
Build a tiny plugin-style registry in C where features register themselves automatically before main() starts. This demonstrates a realistic use of __attribute__((constructor)): self-registration without needing manual setup calls in main().
Goal
Create a program where two features register automatically at startup, and main() prints the registered feature names.
Requirements
- Create a global registry that stores a few feature names.
- Write a helper function to add a feature name to the registry.
- Use at least two functions marked with
__attribute__((constructor))to register features. - Print all registered features inside
main(). - Add one
__attribute__((destructor))function that prints a shutdown message.
Keep learning
Related questions
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.
C Pointer to Array vs Array of Pointers: How to Read Complex Declarations
Learn the difference between pointer-to-array and array-of-pointers in C, plus a simple rule for reading complex declarations correctly.