views:

710

answers:

8

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.

+2  A: 

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 :)

Piotr Dobrogost
Wrapping it in an anonymous namespace will presumably prevent the name of the class and its instance polluting the namespace (which is a good thing) but it doesn't really help make the code less verbose...
Matthew Murdoch
A: 

Sure, you put this in one of your your header files, say preinit.h:

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

and then, in one of your compilation units, put:

void initialize(void) {
    // weave your magic here.
}
#include "preinit.h"

I know that's a kludge but I'm not aware of any portable way to do pre-main initialization without using a class constructor executed at file scope.

You should also be careful of including more than one of these initialization functions since I don't believe C++ dictates the order - it could be random.

I'm not sure of this "sketch" of which you speak but would it be possible to transform the main compilation unit with a script before having it passed to the compiler, something like:

awk '{print;if (substr($0,0,11) == "int main (") {print "initialize();"};}'

You can see how this would affect your program because:

echo '#include <stdio.h>
int main (void) {
    int x = 1;
    return 0;
}' | awk '{
    print;
    if (substr($0,0,11) == "int main (") {
        print "    initialize();"
    }
}'

generates the following with the initialize() call added:

#include <stdio.h>
int main (void) {
    initialize();
    int x = 1;
    return 0;
}

It may be that you can't post-process the generated file in which case you should ignore that final option, but that's what I'd be looking at first.

paxdiablo
A solution doesn't need to be portable. It only needs to work using avr-gcc.
Matthew Murdoch
A: 

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;
Cătălin Pitiș
That is more verbose, not less.
anon
This idea makes me wondering if the order of initialization of static members across class *hierarchy* is defined in C++? If so that would be a way to tackle "static initialization order fiasco".
Piotr Dobrogost
@Piotr: The order of initialization in a translation unit is defined as "the order the definitions appear". Between translation units its undefined.
Richard Corden
@Catalin: static members are initialized exactly as for non local objects, ie. guaranteed to be initialized before they're used, but not necessarily before main. Your example basically has the same behaviour as the example in the question. (See 9.4.2/7 which refers back to 3.6.2, 3.6.3).
Richard Corden
+2  A: 

If you are using the Arduino environment, is there any reason you can't place it in the setup method?

Of course, this is after the Arduino-specific hardware setup, so if you have such low-level stuff that it really has to go before main, then you need some constructor magic.

UPDATE:

Ok, if it has to be done before the main I think the only way is to use a constructor like you already do.

You can always make a preprocessor macro of it:

#define RUN_EARLY(code) \
namespace { \
    class Init { \
        Init() { code; } \
    }; \
    Init init; \
}

Now this should work:

RUN_EARLY(initialize())

But it's not really making things shorter, just moving the verbose code around.

CAdaker
+1, but unfortunately I can't use setup() for this. I'll update the question to make this clear.
Matthew Murdoch
+4  A: 

You can make the above very slightly shorter by giving "initialize" a return type, and using that to initialize a global variable:

int initialize();
int dummy = initialize();

However, you need to be careful with this, the standard does not guarantee that the above initialization (or the one for your init object) takes place before main is run (3.6.2/3):

It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the first statement of main.

The only thing that is guaranteed is that the initialization will take place before 'dummy' is ever used.

A more intrusive option (if it's possible) might be to use "-D main=avr_main" in your makefile. You could then add your own main as follows:

// Add a declaration for the main declared by the avr compiler.
int avr_main (int argc, const char * argv[]);  // Needs to match exactly

#undef main
int main (int argc, const char * argv[])
{
  initialize ();
  return avr_main (argc, argv);
}

At least here you're guaranteed that the initialization will take place when you expect.

Richard Corden
Unfortunately the Arduino environment controls the execution of the compiler so there is no makefile which I can alter.
Matthew Murdoch
+1  A: 

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

Hasturkun
Unfortunately I have no control over the gcc (actually avr-gcc) command line as this is handled automatically by the Arduino environment.
Matthew Murdoch
+5  A: 

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()
Adam Rosenfield
+1 Simple and neat. Does this definitely work on avr-gcc too?
Matthew Murdoch
I don't know for sure, since I've never used avr-gcc, but according to this page http://www.nongnu.org/avr-libc/user-manual/porting.html , avr-gcc supports other types of attributes.
Adam Rosenfield
I've tried this using the Arduino software (which is backed by avr-gcc) and it works. I'll accept this answer, thank you.
Matthew Murdoch
+1  A: 

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).

wesen