How can I perform pre-main initialization in C/C++

2020-02-19 17:53发布

In order to ensure that some initialization code runs before main (using Arduino/avr-gcc) I have code such as the following:

class Init {
public:
    Init() { initialize(); }
};

Init init;

Ideally I'd like to be able to simply write:

initialize();

but this doesn't compile...

Is there a less verbose way to achieve the same effect?

Note: the code is part of an Arduino sketch so the main function is automatically generated and cannot be modified (for example to call initialize before any other code).

Update: ideally the initialization would be performed in the setup function, but in this case there is other code depending on it which occurs before main.

9条回答
太酷不给撩
2楼-- · 2020-02-19 18:05

Use static members of classes. They are initialized before entering to main. The disadvantage is that you can't control the order of the initialization of the static class members.

Here is your example transformed:

class Init {
private:
    // Made the constructor private, so to avoid calling it in other situation
    // than for the initialization of the static member.
    Init() { initialize(); }

private:
    static Init INIT;
};


Init Init::INIT;
查看更多
我欲成王,谁敢阻挡
3楼-- · 2020-02-19 18:06

Here's a somewhat evil method of achieving this:

#include <stdio.h>

static int bar = 0;

int __real_main(int argc, char **argv);

int __wrap_main(int argc, char **argv)
{
    bar = 1;
    return __real_main(argc, argv);
}

int main(int argc, char **argv)
{
    printf("bar %d\n",bar);
    return 0;
}

Add the following to the linker flags: --wrap main

eg.

gcc -Xlinker --wrap -Xlinker main a.c

The linker will replace all calls to main with calls to __wrap_main, see the ld man page on --wrap

查看更多
Root(大扎)
4楼-- · 2020-02-19 18:07

You can use GCC's constructor attribute to ensure that it gets called before main():

void Init(void) __attribute__((constructor));
void Init(void) { /* code */ }  // This will always run before main()
查看更多
Bombasti
5楼-- · 2020-02-19 18:09

There is how I perform pre-main coding. There are sever init sections executed before main, refers to http://www.nongnu.org/avr-libc/user-manual/mem_sections.html initN sections.

Anyhow, this only works on -O0 optimization for some reason. I still try to find out which option "optimized" my pre-main assembly code away.

static void
__attribute__ ((naked))
__attribute__ ((section (".init8")))    /* run this right before main */
__attribute__ ((unused))    /* Kill the unused function warning */
stack_init(void) {assembly stuff}

Update, it turns out I claimed this function is unused, leading to optimize the routine away. I was intended to kill function unused warning. It is fixed to used used attribute instead.

查看更多
兄弟一词,经得起流年.
6楼-- · 2020-02-19 18:16

You can use the ".init*" sections to add C code to be run before main() (and even the C runtime). These sections are linked into the executable at the end and called up at specific time during program initialization. You can get the list here:

http://www.nongnu.org/avr-libc/user-manual/mem_sections.html

.init1 for example is weakly bound to __init(), so if you define __init(), it will be linked and called first thing. However, the stack hasn't been setup, so you have to be careful in what you do (only use register8_t variable, not call any functions).

查看更多
趁早两清
7楼-- · 2020-02-19 18:18

Your solution in simple and clean. What you can additionally do is to put your code in anonymous namespace. I don't see any need to make it better than that :)

查看更多
登录 后发表回答