3.5.2 How Can I Make My Code Smaller?
There are a number of ways that this can be done, but results vary from one project to the next. Use the assembly list file (see 6.3 Assembly List Files) to observe the assembly code, produced by the compiler, to verify that the following tips are relevant to your code.
Use the smallest data types possible, as less code is needed to access these (this also reduces RAM usage). Note that a bit type and non-standard 24-bit integer type exists for this compiler. Avoid multi-bit bit-fields whenever possible. The code used to access these can be very large. See 5.3 Supported Data Types and Variables for all data types and sizes.
There are two sizes of floating-point type when using C90, with these being discussed in the same section as well. Avoid floating-point if at all possible. Consider writing fixed-point arithmetic code.
Use unsigned types, if possible, instead of signed types; particularly if they are used in expressions with a mix of types and sizes. Try to avoid an operator acting on operands with mixed sizes whenever possible.
for(i=0; i!=10; i++)
is preferable
to:for(i=0; i<10; i++)
A check for equality (==
or !=
) is
usually more efficient to implement than the weaker <
comparison.
for(i=10; i!=0; i--)
char calc(char mode, int value);
overchar calc(int value, char mode);
struct MYSTRUCT {
int popular; // access to this member occurs throughout the program
int avoided; // the following members can be placed in any order
int unliked;
} myStruct;
struct MYSTRUCT * stp = &myStruct;
Indirectly accessing structure members
requires a runtime addition of the structure's base address and member offset; however,
when accessing the first member, that offset is zero, and so the addition is not
required. This makes the access code smaller and faster.char myArray[2][5];
and access an
element using the code myArray[x][y]
, this performs an operation
equivalent to the C
expression:*(&myArray + y + x * 5)
This
involves a multiplication by 5 (the number of elements in the second dimension). If your
target device does not implement a hardware multiply instruction, this multiplication
might involve a call to a library routine. If the array had been instead defined with
the dimensions
swapped:char myArray[5][2];
then
accessing the myArray[x][y]
element would be equivalent to the C
expression:*(&myArray + y + x * 2)
which
involves a more-friendly multiply by two. This is often performed with a simple
shift.In the same way, accessing an element of a single-dimension array of structures will require multiplication by the structure size. If for example you had an array of structures and each structure was 3 bytes long, adding an extra byte to the structure would increase the size of the memory required to store the array, but accessing elements that were 4 bytes wide might be faster than accessing elements that were 3 bytes wide.
Ensure that all optimizations are enabled (see 4.6.6 Options for Controlling Optimization). Be aware of what optimizations the compiler performs (see 5.13 Optimizations and 6.2 Assembly-Level Optimizations) so you can take advantage of them and don’t waste your time manually performing optimizations in C code that the compiler already handles, e.g., don’t turn a multiply-by-4 operation into a shift-by-2 operation as this sort of optimization is already detected.