1) Avoid passing long argument lists to functions. Avoid returning long values from functions. The most efficient function types to use are void, int, or pointer.
2) Avoid initializing global variables within a small function. Instead, assign a value during variable definition.
3) Avoid converting chars to another type. char variables can be located anywhere in RAM, while word variables can only be at even addresses. Because of this, the code will result in unpredictable CPU behavior.
4) Use int instead of char or unsigned char if you want a small integer within a function. The code produced will be more efficient, and in most cases storage isn’t actually wasted.
5) Try to minimize the use of addition and subtraction with floating point numbers. These are slow operations.
6) Use shift instead of multiplication by constants which are 2^N (actually, the compiler may do this for you when optimization is switched on).
7) Use unsigned int for indices – the compiler will snip _lots_ of code.
8) Use ‘switch/case‘ constructs rather than a chain of ‘if/else‘ constructs.
9) Use logical or (‘|’) rather than ‘+’ for bit masks.
10) When defining bit fields, try to use signed integers. This produces more compact code that bit fields of unsigned integers.
11) Use ‘alloca‘ instead of ‘malloc‘ for locals. In embedded applications trying to avoid any dynamic memory allocation is usually even better.
12) Delay loops are very sophisticated routines. Developers often do something like:
|int i = 1234;
for (i = 0; i < 1234; i++);
NEITHER WILL WORK AS YOU EXPECT when optimization is switched on!!! The optimizer will detect dead code in both examples and will eliminate it. It might even eliminate the loop completely. Adding the volatile attribute to the definition of ‘i’ might help, but don’t count on it if ‘i’ is a local variable. The compiler can still detect the calculations are wasteful, and eliminate them.
– Pranam Lashkari