Programming tips and trics

As a newbie on Arduino I still have some learning to do. But as a programmer I have been there for a while. So I have noticed some habits in Arduino programming; I am not going to say these are good or bad habits. I am just going to wonder if "doing the things you do is the best way to do it".

The most common way to set up a sketch is:

{declare a bunch of constants and variables}

void setup{
setup pins
setup other stuff
setup interrupt handler
run through some code
}

void loop {
stuff the loop part with code
and more code
and some more code
}

Declaring the constants and variables in the above part of the code means that one is allocating memory during the time the sketch runs. So you have ask yourself if that's necessary, maybe you use that specific variable just once.

First wonder if it's necessary to declare a constant, maybe you could use #define instead. The define statement is a compiler directive, which means the compiler will translate the defined label into it's value everywhere it exists in your code. Meaning that it won't allocate memory.

Second: if one is using a variable or a constant just once it may be possible to declare a variable locally. (= in a function.) Which has the advantage that the memory will be freed once the function is finished.

Third: sometimes it wise to pass a variable to a called function. Advantage is that you keep track of where a variable is used and the variable will be passed using the stack instead of the data area and that it's often possible to pass a direct value instead of a variable.

Example:
void myFunc(int myVariable){
//do some stuff
}

You can call this function with
myFunc(123)

The preprocessor is soooooo 1970s.

You'll be astonished about how good the compiler is at optimisation.

1 Like

#define is deprecated for that use. C++ has better means for this purpose: const or even better constexpr.
But I admit that this is used rarely by beginners - I think especially because it is not used in the examples - presumable to keep it simple for beginners. But if you want to give tips, they shoud'nt be outdated :wink:

It still useful and needed for some aspects. But indeed not to define constant values :sunglasses:.

1 Like

Here's a quirk of mine (not sure if this is universal). I put my functions after the main loop. Sometimes I even put them in another INO file.

1 Like

My understanding is as follows

Suppose I declare a constant then use the value multiple times in the sketch, then the value of the constant is stored in memory once and accessed multiple time

If, however, I use #define to replace the value throughout the sketch, then effectively the variable is stored in memory multiple times

Is that correct ?

However, the compiler will come into play and optimise the code and may well put the constant in a register, thus using no memory to hold it at all. Can it do that with a #defined value ?

No. If you use a #define the preprocessor - which at least is a automatic text editor - will replace all occurences of that name with the constant number. The compiler doesn't see that at all. The preprocessor runs first, and the result is presented to the compiler.
From the compilers point of view it's the same as if you would write 'magic numbers' at all occurences.

If you use constexpr to define a constant value, the compiler will handle that and can do e.g. type checking. Of course the compiler does not store the value in RAM but will it use directly as appropriate.

To discard a variable after using it locally, it can be declared ‘locally’

Read up on the SCOPE of variables.

That's what I am saying.

I have to agree that I think that too many of the worked examples make inappropriate use of global scope, but scope is a tricky concept for non-programmers.

I don't think I've ever seen an intuitive real-world analogy.

Coming from the Delphi and Embarcadero world, I am most of all astonished by how slow the compiler is :stuck_out_tongue:

Exactly, but can the compiler optimise them all into a single location in memory or a register ?

You're not from round here, are you? :joy:

When there's a freely available Delphi compiler for AVR, maybe I'll take a look.

I doubt the compiler would waste a register* on a constant, but small constants will become immediate literal constants as part of the instruction.

*Though some architectures do, retaining common constants as special purpose registers

What are you replying to ?

Strictly speaking, those variables are allocated (and initialised) during crt0, which occurs before main() is called, and so before setup(), so before the time the sketch runs.

Who is the intended receiver of these tips and tricks? The people that can understand what this all about already know it.

1 Like

...which is why I've asked for this to be moved - it isn't any kind of tutorial

1 Like

The 'advantage' of using all globals and no locals is that the IDE can warn you that you have run low on RAM without waiting for it to crash while running.

One disadvantage is that it makes it too easy for the variables to be used in conflicting ways. For example, using a global named 'i' for all you 'for' loop indexes and having one loop call a function that contains another loop.

Declaring the constants and variables in the above part of the code means that one is allocating memory during the time the sketch runs.

Well, no. They are allocated at compile time. They may be initialized when the sketch starts, if they haven't been optimized away.
Assigning names to constants is good for program readability, of course.

First wonder if it's necessary to declare a constant, maybe you could use #define instead.

As others have said, static const int x = const; is preferred over #define x const Because it is typed, and strong typing fixes everything, or some-such koolaid. In any case, it is just as unlikely to actually allocate memory as a #define, given today's compilers.

Second: if one is using a variable or a constant just once it may be possible to declare a variable locally. (= in a function.) Which has the advantage that the memory will be freed once the function is finished.

Alas, you can't count on this. In the interest of speed, the compiler will aggressively combine (inline) functions, so the two functions you wrote, each allocating 100bytes of memory, may be merged into a single function that allocates 200bytes of memory. Or maybe not.
MOST local variables are likely to allocated to registers, rather than memory.

Actually using stack frames on an AVR is annoyingly "expensive." About the only time the stack is actually used for passing function arguments is when a function has a variable number of arguments.


IMNSHO, the nature of deeply embedded programs tends to favor global variables.

Also IMO, the examples tend to under-utilize the use of functions in general, regardless of how they pass their data around.

Are they? According to some answers I doubt that.