1

I've got a question concerning the Arduino library "RTClib" by Adafruit and the use of the word "static".

Here you can see an excerpt from the example provided for the pcf8523 real-time clock:

#include "RTClib.h"

RTC_PCF8523 rtc;

void setup () {

  while (!Serial) {
    delay(1);  // for Leonardo/Micro/Zero
  }

  Serial.begin(57600);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.initialized()) {
    Serial.println("RTC is NOT running!");
  }
}

void loop () {
    DateTime now = rtc.now();

    Serial.print(now.year(), DEC);
    /*
    do some more stuff
    */
}

In the beginning of loop() they wrote:

DateTime now = rtc.now();

Thus, with every iteration of loop() "new" gets defined anew (on the heap?!), right? This appears inefficient to me.

I thought about rewriting it this way:

static DateTime now;    // static declaration, executed only once
now = rtc.now();    // assignment to "now" every time loop() starts over

In this case "new" should be allocated on the stack like a global variable, right?

I want to use "static" to increase overall performance by reducing work for the processor and the heap (thereby avoiding heap fragmentation). Does this make sense or will it cause more problems than it solves? Keep in mind that I want to learn both proper programming for Arduino and proper coding in general.

Link to the library: https://github.com/adafruit/RTClib

Thank you! :-)

EDIT: For some reason I CAN NOT declare DateTime now; in global scope or else the program won't run. Don't know why though. This is why I want to use static in the first place.

6
  • 3
    Re “I CAN NOT declare DateTime now; in global scope”: what happens if you do so? A compilation error? Incorrect run-time behavior? I tried and it compiles just fine (but I have no RTC for testing). – Edgar Bonet Apr 22 '20 at 20:28
  • Actually, DateTime now = rtc.now() might have utilize "copy elision", so it gets constructed directly into now variable and therefore it's faster than your approach (as you effectively blocked this possibility - so it has to create temporary object and copy it into now variable). – KIIV Apr 22 '20 at 21:51
  • @EdgarBonet , it compiles and uploads but will not execute Setup(). Setup() starts with Serial.begin(9600); Serial.println("test"); Blinking the builtin-led doesn't work either. – blackdaw Apr 23 '20 at 17:05
  • @KIIV , concerning C++ I've read many times that separate declaration and definition can be part of "good practice". Your explanation was never mentioned but seems to make sense! Maybe it makes no difference with (aggressive) compiler optimization? – blackdaw Apr 23 '20 at 17:13
  • @blackdaw I'm pretty sure it's about declaration and definition of Class methods, not variables. And non rules/myths: Don't insist that all declarations shoudl be at the top of function and two rules Don't introduce a variable (or constant) before you need to use it – KIIV Apr 23 '20 at 17:26
3

You wrote:

DateTime now = rtc.now();

Thus, with every iteration of loop() "now" gets defined anew (on the heap?!), right?

No. Local variables like this are usually allocated on the stack, although the compiler may keep them in CPU registers if that helps optimization.

static DateTime now;    // static declaration, executed only once

In this case "new" should be allocated on the stack like a global variable, right?

No. It is allocated statically, in the .bss section, like uninitialized global variables.

I want to use "static" to increase overall performance by reducing work for the processor

Not sure it will make much difference. Static allocation may save you a few CPU instructions compared to stack allocation (the instructions that move the stack pointer). On the other hand, it will cost you a few instructions compared to register allocation (the instructions to access the RAM).

avoiding heap fragmentation

Stack allocation does not use the heap, and the stack never fragments.

Does this make sense or will it cause more problems than it solves?

If you really care about sub-microsecond differences in the execution time, you should either look and the disassembly of the program, or do some benchmarking. Otherwise just write whatever makes more sense from the point of view of the program's logic: does the variable need to keep its value across calls to loop()? If the answer is “no”, do not use static.

0

You don't need to use the static keyword.

The cleanest solution is to define DateTime outside of the loop function:

DateTime now;

This will allocate the memory, and call the constructor of the class DateTime initializing it.

In case you would need a basic variable (like an int), you should initialize it, like:

int now = 0;

When you use it in setup or loop you use the created instance (without the class name to declare it):

void loop() {
   ...
   now = rtc.now();
}

Also, find a better name for now, because the variable is the same as the rtc's function now.

Update

after your comment, it cannot be used as a global variable:

I didn't try it myself, but I suspect, the constructor calls a function that uses variables or a function that is not initialized at that point. Actually, it's quite bad practice.

Anyway, one way to circumvent and stick as much to what I wrote above, is to use a pointer instead:

RTC_PCF8523* rtc = NULL;

Than you create an empty pointer, without calling the constructor. You will do this at the end of setup:

void setup() {
   ...
   rtc = new RTC_PCF8523();
}

This will cause the variable to be put on the stack.

Than when using it, you call:

now = rtc->now();

Note you have to use the -> notation, as rtc is a pointer.

5
  • 1
    Forgot to mention: Defining it outside of loop() in the global scope DOES NOT WORK! Don't ask me why, I spent hours just to find this problem. This is the reason why I wanted to use static in the first place. Will edit my post. And concerning the name "now": It's just what they used in the example, I won't use it, but good point! – blackdaw Apr 22 '20 at 19:54
  • I updated my answer, just try if it helps. – Michel Keijzers Apr 22 '20 at 20:10
  • 1
    Re “I suspect, the constructor calls a function that uses variables or a function that is not initialized at that point”: I can't see anything wrong in this constructor. – Edgar Bonet Apr 22 '20 at 20:34
  • @EdgarBonet ... me neither, I'm wondering why creating it as global variable wouldn't work. – Michel Keijzers Apr 22 '20 at 20:36
  • See the comments above beneath @EdgarBonet 's solution. It compiles and uploads but doesn't execute. – blackdaw Apr 23 '20 at 17:16

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.