2

Apologies if this has been discussed before but I couldn't find anything.

I have written a simple LED class. For illustration (it is actually a bit more complex) but it goes something like;

class LED {
    LED(byte pin);
  private:
    int _pin;
};

And the constructor is simply;

LED::LED(byte pin) {
    _pin = pin;
};

and I create a global instance of this class at the top of my code thus;

LED redLED(5);

It is necessary to create this as a global object because (a) I can't create the object in the setup() function because it would go out of scope and (b) I can't create in the loop() function because I don't want to create an infinite number of these objects.

This all seems to work OK but it just leaves me wondering exactly when this constructor gets executed? I suppose that it must be before setup()?

Answered!

Many thanks to all the respondents. So when using the Arduino IDE the build process must silently insert the main() procedure. I was not aware that it did this. I guess that most of the time you can get away with not knowing when the global constructors are called.

It is good practice (I think) to create a "wrapper" class for all/any external (or perhaps internal) hardware devices that are connected to your arduino. And it is thus perhaps tempting (but risky) to do initialisation work in the constructor.

So given what I now know, it is better to create an "init()" method for such classes that can be called from setup(). Even if just to do the the pinmode() call.

Thanks again.

1
  • Re “the build process must silently insert the main() procedure”: It is provided by the Arduino core library. Re “it is better to create an ‘init()’ method”: It would seem that begin() is the canonical name for such a method. – Edgar Bonet Dec 19 '20 at 17:10
3

The global constructors run right after the initializations performed by the C runtime startup code, and right before main() gets called.

In a nutshell, the C runtime initialization code:

  • does some low-level initializations (e.g., setup the memory)
  • calls the global constructors
  • calls main(), which in turn
    • calls init() to do the Arduino-specific initializations
    • calls setup()
    • repeatedly calls loop()

The fine details are probably platform-specific. For AVR-based boards, they are documented in the avr-libc manual.

1

It is executed before the main() is called (in the main() there is setup() called and then loop() is called in infinite loop).

It has its own sections for the constructors and destructors: http://beefchunk.com/documentation/sys-programming/binary_formats/elf/elf_from_the_programmers_perspective/node4.html

0
class LED {
private:
  const byte _pin;
public: 
  LED(const byte pin);
};

With an even simpler c'tor:

LED::LED(const byte pin) : _pin(pin) {};

To be a bit on-topic: The initializer list is even executed before the constructor body, and is thus the way to initialize constants.

Question remains whether it's guaranteed that this works:

class LED {
private:
  const byte _pin;
public;
  LED(const byte pin) : _pin(pin) {pinMode(_pin,OUTPUT);}
  set(bool state) {digitalWrite(_pin, state); }
};

( Can pinMode be called that early, or should one invent an init() method? )

My experience says : works well ...

2
  • Note that the constructor runs before the Arduino core is initialized. Are you sure it works well on every Arduino board? On AVR, it sure does, because pinMode() happens to not rely on the Arduino core being ready. – Edgar Bonet Dec 19 '20 at 13:45
  • I have only tested this on a Nano – Rob W Dec 19 '20 at 15:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.