Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Imitating constructor of static objects in C

Tags:

c++

c

constructor

I want to have a global names variable, which looks like that

char* names[NAMES_CAP];
int names_len = 0;

And I want every one who links to this library to be able to add an item to this list.

It's easy to do that from main.

int main(int argc,char**argv) {
    names[names_len++] = "new name";
    names[names_len++] = "new name 2";
}

but what if I want to stack up two libraries? (ie, my library, libnames holds the global variable. And if someone links to libnameuser who uses libnames, it will automatically add all names defined in libnameuser to the names array in libnames.

Is there any way to do that?

In C++, I can insert the names[names_len++] = "..." to the constructor of a global object, and it must be called. But can I do that with plain C?

like image 384
Chi-Lan Avatar asked Oct 21 '11 11:10

Chi-Lan


2 Answers

If you are using gcc you can use the constructor attribute __attribute__((constructor)) to get the same effect. This is however non-standard C.

I would however recommend against this pattern since there is no control of ordering of any function run before main. I would rather find a nice method of hooking in all the "constructor" functions after main has started running.

like image 112
doron Avatar answered Sep 30 '22 14:09

doron


Update: Refer to https://stackoverflow.com/a/2390626/270788 for updated version of this answer.

Below is a pre-processor abstration to support C static initializer functions with GCC and MSVC. The GCC version will also work with LLVM CC, maybe some other compilers as well.

The MSVC version works by placing a ptr to the static initializer function in a special section that is processed by the application or DLL startup code.

#if defined(__GNUC__)
  #define INITIALIZER(f) \
    static void f(void) __attribute__((constructor)); \
    static void f(void)
#elif defined(_MSC_VER)
  #define INITIALIZER(f) \
    static void __cdecl f(void); \
    __declspec(allocate(".CRT$XCU")) void (__cdecl*f##_)(void) = f; \
    static void __cdecl f(void)
#endif

INITIALIZER(initializer_1) { names[names_len++] = "new name"; }
INITIALIZER(initializer_2) { names[names_len++] = "new name 2"; }
like image 30
Joe Avatar answered Sep 30 '22 13:09

Joe