Welcome back dear readers, here is another treat for you. This one is related to optimizations/best practices in C/C++ code. The optimizations here are not much significant for modern personal computers/laptops. But these can be crucial in case of real time embedded systems and in case of low memory devices. But even if they don’t provide noticeable effects in case of powerful computers they still are good practices to follow while writing C/C++ code even for these devices. So, lets get started.
Limit the number of parameters to a function
The number of parameters you pass to a function affects the efficiency of your code. Whenever you call a function, its parameters are to be pushed on the stack. This adds overhead if there are a lot of parameters to be pushed.
Also, avoid passing structures as parameters instead just pass their pointers or references. This is to be done to avoid large structures to be pushed on the stack. A single structure may require multiple push statements.
In case of object parameters in C++, copy constructor is called adding a lot of overhead. So, it is better to pass objects as const references to functions.</li>
Limit the number of local variables used inside a function
Just like arguments are pushed on to the stack, local variables are also stored on the stack frame of the called function and space is to be allocated for them. Then to access these local variables and parameters of the function offsets from a register called the frame register are used (How a function is called in C?). This adds a lot of overhead.
To avoid these overheads, you can minimize the number of local variables you use. This allows compiler to store the local variables inside a CPU register instead of setting up the frame pointer.</li>
Adjust struct sizes to power of two
In case of struct arrays, indexing is to be performed to access each member. If the sizes of struct are in power of 2, then indexing becomes a shift operation, which is quite easy for the CPU.</li>
Use case labels in narrow range and put frequent cases first
Use int instead of char and short
Many programmers tend to use char and short for their variables that take smaller values, thinking that it saves space. But actually it is not always the case. Your memory may be aligned to 32 bits (4 bytes) and hence even char and short may be stored in 4 bytes. Therefore, the space may not always be saved.
Secondly, the operations on char and short, like addition, multiplication, etc, are performed by first converting them to int values (Read more about integer promotion). So, this may also add some overhead to convert to int and then back to the original type.</li>
Constructors should be short and simple
Another good practice is to keep your constructors lightweight. Avoid doing too many things inside a constructor. The constructors are called at a lot of places, when creating/copying objects, returning objects, for temporary objects, etc. In case of arrays they are called separately for each element. So, avoid doing too many things inside a constructor.</li>
Use constructor initialization lists
In case of classes that have objects of other classes as their members, it is better to initialize these members by calling their respective constructors in the initialization list of the class’ constructor. This avoids extra overhead of initializing the object members of the containing class inside the constructor because constructors for the member objects are called anyways.</li>
Using inline functions avoids the overhead of calling the function thus improving efficiency. Inline function calling is equivalent to including the function’s code at the place of calling. But there are a few things that one must keep in mind when making functions inline.
- Only inline short functions. If we make long functions inline it causes code bloating.
- Also don’t inline frequently called functions even if they are short due to the same reason above.
So, that’s all for this post. Hope you liked it. Comment below if you have anything to say.