Arduino General Best Practices

I have noticed different coders use a void function before the void setup, after it, and after the loop. What's the difference in putting it in different places? Is there a difference in the performance and reliability of the code? What is best to declare first when listing your variables? In some applications variables declared before another can make the processor respond quicker. Does anyone know a good order here? I would think int would be first, double, float, char?...etc Any intake? Global and local variables.

void is not a function. It just tells the compiler that a call to a function is not expecting a return value as in "void setup()"
or that a function will not be receiving any parameters as in the second void in this

"void setup(void) { 
}

The empty "()" implies void.

As for the rest I suggest two approaches which are not mutually exclusive "suck it and see" and "if it works don't fix it"

...R

In pure C or C++ the order you have your functions is important. You have to declare a function before you can use it, so:

void main() {
  doSomething();
}

void doSomething() {
  // ...
}

won't compile. Sometimes it's not possible to do things in the exact right order, so you have the possibility of adding a function "prototype" before the function is actually defined, which allows you to use the function even though the compiler may not have reached the actual function code yet. So changing it to:

void doSomething();

void main() {
  doSomething();
}

void doSomething() {
  // ...
}

will compile.

Now, the Arduino IDE hides all this from you. One of the first things it does when you compile is scan through the code trying to identify any functions. It then compiles a list, and creates function prototypes and adds them to the top of your sketch for you. That way you can define and use your functions in any order whatsoever and it won't make the slightest bit of difference.

So to answer your first question: It doesn't matter, Arduino goes off and does its own thing to make life simpler for the beginner.

The order you define variables doesn't have a performance impact as far as I know. The size of variables, however, can have a big performance impact. If you're working with small numbers (<= 255) and you're storing them in an int, then you're adding a huge amount of processing overhead for just the simplest of operations. Also, the scope of the variable can have an effect on memory consumption. Global, or local-static variables will always have their memory allocated whether you're actively using them or not. Pure local variables will only exist when you are in the function they are declared in (or a function called from that function, etc), and their memory is released as soon as you leave the function. So it's best to always keep the scope of the variables as small as possible so the memory can be reused as much as possible.

So to answer your second question: Order doesn't matter, but size and scope does.

Order of the variables is important with regards to the function ordering mentioned above. C++ is compiled linearly, and a symbol must be declared before it is used.

int a = 1;
int b = c + a; //Error, c not declared
int c = b + a; //Fine

Non-Arduino C++ has different implications. Arduino being 8-bit allows you to avoid some of the headaches associated with alignment of data. Hopefully some of you find this interesting.

Ordering of class members is important when using systems with alignment boundaries greater than 1 byte.
For instance 32-bit windows has 4-byte alignment which means padding could be used to correctly align a structure.

Consider the two structures with the same contents, just laid out differently.

//int is 4 bytes on 32-bit systems.
struct A{
  char a;
  char b;
  int c;
  char d;
  char e;
};

struct B{
  char a;
  char b;
  char c;
  char d;
  int e;
};

In this example, sizeof( A ) == 10, whereas sizeof( B ) == 8.
This is due to padding being inserted after A::b to correctly align A::c.

There is even more consequences that meet the eye. As the sizeof( A ) is not a multiple of 4, if the structure was used in a class itself like below:

struct C{
  A a;
  int b;
};

Then if the next member is of system width or larger, it will be offset further to be in alignment.
sizeof( C ) == 16 bytes.

Whereas if we used an optimally aligned structure like struct B:

struct D{
  B a;
  int b;
};

Then each member is correctly aligned without padding and sizeof( D ) == 12 bytes and contains the 'same' structure as C.

You can force the removal of all padding in your structures by turning on the "packed" attribute:

struct A{
  char a;
  char b;
  int c;
  char d;
  char e;
} __attribute__((packed));

This is especially useful when you are creating a struct to overlay over incoming data.

1 Like

majenko:
You can force the removal of all padding in your structures by turning on the "pack" attribute
This is especially useful when you are creating a struct to overlay over incoming data.

You can achieve the same in other compilers using #pragma pack 1, however neither of these are completely portable.