I was wondering if it's possible to use C constructors in VC just as it is possible to use them in GCC.
The gcc way is quite straight using the __attribute__
keyword, unfortunately VC doesn't seem to even know this keyword, as I'm not a Win32 programmer I wonder if there's some sort of equivalent keyword for such things.
Just to note - this is a C program, not a C++ or C# even, (as 'twas quite easy to do that in those languages)
Asked
Active
Viewed 1.8k times
38

Cœur
- 37,241
- 25
- 195
- 267
-
1for those of us who haven't used it, what does it do? (And what do you need it for?) – jalf Jul 11 '09 at 13:24
-
Any function marked as `constructor` is run by the dynamic linker as it loads the object. – Adam Goode Apr 28 '10 at 03:12
-
@:Jalf: [How exactly does attribute constructor work?](http://stackoverflow.com/questions/2053029/how-exactly-does-attribute-constructor-work) – Casebash Sep 22 '10 at 07:36
4 Answers
48
Below C code demonstrates how to define a void(void) function to be called at program/library load time, before main executes.
For MSVC, this places a pointer to the function in the user initializer section (.CRT$XCU), basically the same thing the compiler does for the constructor calls for static C++ objects. For GCC, uses a constructor attribute.
// Initializer/finalizer sample for MSVC and GCC/Clang.
// 2010-2016 Joe Lowe. Released into the public domain.
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
#define INITIALIZER(f) \
static void f(void); \
struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
static void f(void)
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
static void finalize(void)
{
printf( "finalize\n");
}
INITIALIZER( initialize)
{
printf( "initialize\n");
atexit( finalize);
}
int main( int argc, char** argv)
{
printf( "main\n");
return 0;
}

Joe
- 881
- 7
- 7
-
Hi Joe: great post! I really need the tricks for working with VC. It's critical to auto-register a unit test function in C(not C++). BTW: There should be a tailing \ in the second line of macro INITIALIZER – zhaorufei Sep 27 '10 at 01:04
-
3Such constuctors will be optimized out in new Visual Studio release builds. Its rerely known and unfortunately unsolved bug. The only workaround I found so far: Project properties > C / C++ > Optimization > Whole Program Optimization(/ GL) must be disabled. – user3042599 Oct 08 '15 at 16:27
-
I'm experiencing the same problem as described above so don't just copy paste above code assuming it will just work. – CrHasher Nov 20 '15 at 09:32
-
GLib recently switched from using `.CRT$XCU` section to using `DllMain` for this reason: https://bugzilla.gnome.org/show_bug.cgi?id=752837 – Amro Dec 21 '15 at 23:26
-
2@user3042599. Thanks for the heads up on the issues with MSVC 2015 link-time optimizations. I have edited the code sample and it should not have issues, though it now requires MSVC 2008 or later due to use of __pragma() . – Joe Jan 30 '16 at 22:22
-
Hi, sorry to resurrect an old thread... I have this same issue, the function is: ` void __attribute__((constructor)) init() { // Setup GPU Memory Management cuda::gpu_mat_allocator = new cuda::Allocator(); // cv::cuda::GpuMat::setDefaultAllocator(cuda::gpu_mat_allocator); }` I have used the above sample, with: ` INITIALIZER(initialize) { cuda::gpu_mat_allocator = new cuda::Allocator(); atexit(finalize); }` is that correct? – anti May 27 '17 at 10:18
-
Just as a wee, tiny, nigh insignificant little niggle, I'd suggest changing `__attribute__((constructor))` to `__attribute__((__constructor__))`. This is a macro here, so there's no convenience lost this way, and it avoids the theoretical possibility of some lunatic defining `constructor` to something else. Obviously defining `__constructor__` to something stupid would be non-compliant, so it's safer. – Roflcopter4 Jun 06 '21 at 08:53
5
-
It must be executed _before_ entering main(), that's for dlls, how's that related ? :/ – Jul 11 '09 at 10:43
-
About the only real use people have for __attribute__((constructor)) is to use them in shared libraries similar to emulate a DllMain :) – nos Jul 11 '09 at 11:00
-
7`__attribute__((constructor))` is useful even in a single program image; for example, inserting global hooks around library and system calls, or registering built-in "plugins", or initializing data structures that dynamically linked modules will need in their "`DllMain`"-alikes. – ephemient Jul 11 '09 at 16:18
5
I don't think there's a way to avoid using C++ features with MSVC. (MSVC's C support sucks anyways.)
Untested, but this should at least allow the same code to work in both MSVC and GCC.
#if defined(_MSC_VER)
struct construct { construct(void (*f)(void)) { f(); } };
#define constructor(fn) \
void fn(void); static constructor constructor_##fn(fn)
#elif defined(__GNUC__)
#define constructor(fn)
void fn(void) __attribute__((constructor))
#endif
static constructor(foo);
void foo() {
...
}

ephemient
- 198,619
- 38
- 280
- 391
-
1As far as I can tell this does not work in plain C on MSVC 2013 or 2015. Seems like C compiler mode doesnt support constructors in a struct. I tried to make it work in various ways. – guru_florida Sep 06 '17 at 15:50
2
I tried the last answer in MSVC like
#ifdef _MSC_VER
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
but INITIALIZER(f) can't appear in 2 different files with the same function name passed to INITIALIZER, the following definition will allow that
#ifdef _MSC_VER
#define INITIALIZER(f) \
static void f();\
static int __f1(){f();return 0;}\
__pragma(data_seg(".CRT$XIU"))\
static int(*__f2) () = __f1;\
__pragma(data_seg())\
static void f()
#else
#define INITIALIZER(f) \
__attribute__((constructor)) static void f()
#endif

user7061528
- 21
- 2
-
The linker pragma in my answer is needed, and does have the effect that initializer function names must be unique for the whole exe/dll. See the comments under my example by user3042599, and my response. I am unaware if the change of section name is an alternate solution to the linker pragma, but it will have other side effects. – Joe Dec 19 '18 at 17:31