Embedded code: clear or clever?
When developing embedded code, there are various priorities. Top of the list, obviously, is delivering the required functionality and performance. This can be challenging enough. A key requirement is a clear, unambiguous and stable specification. However, at a lower level, the code developer has lots of everyday decisions to make around a number of sometime opposing priorities …
The design of desktop applications is driven by a single criterion: user satisfaction. So, given the design [the user interface in particular] is up to scratch, the main thing is speed. Embedded systems are different as there may or may not be a UI; the device may or may not be real time; cost can be a big issue. The list goes on, but ultimately it results in some prioritization when implementing the code:
- code for highest performance
- code for predictable performance [deterministic]
- code for minimum size
- code for minimum power consumption
- code for maintainability
Of these, 1-4 are often in tension and finding the balance is the challenge and that depends on the application. To a significant extent these factors are influenced by the higher-level aspects of the implementation: using a real-time operating system, with a power-management framework perhaps; maybe implementing a multicore design. Beyond that, understanding the fine tuning of code generation is worthwhile, as a compiler generally knows best how to achieve many of these goals.
The outlier is #5. Software development is expensive. More time is spent maintaining code [fixing, updating and augmenting] than developing new applications. This means that any effort spent making the code clearer is an investment in the future. There are two bonuses: clearer code is generally more reliable, which means that it needs less maintenance; code written for clarity is very rarely slower or larger than a less clearly expressed algorithm.
Writing clear, maintainable code is possible in most programming languages. Although this may be challenging in, say, Forth of LISP. It is [very] easy to write highly obfuscated code in C, but writing clear code is not difficult. There are numerous coding style guides around and even using a programming standard like MISRA C, that is designed to help make code reliable, tends to lead to more maintainable code. To some extent, a “higher level” language may be helpful, as algorithms may be expressed more naturally. C++ is an obvious possibility. Here is an example:
If an application uses complex numbers, a means to represent them and operate on them is required. In C, a structure makes sense:
struct cx { float real; float imag; };
Then, we can create two variables, initialize them and add one to the other thus:
struct cx x, y; x.real = 1.0; x.imag = 2.0; y.real = 3.0; y.imag = 4.0; x.real += y.real; x.imag += y.imag;
This is reasonably clear and succinct, but can C++ do better? I would say the answer is yes. We can define a class to represent the data, which can include a constructor function to take care of initialization and a function to perform the addition:
class cx { float real; float imag; public: cx(float r, float i) { real = r; imag = i; } void add(cx n) { real += n.real; imag += n.imag; } };
This enables complex variables to be set up and added thus:
cx x(1.0, 2.0), y(3.0, 4.0); x.add(y);
Although this is neater/clearer that C, there is room for improvement. The add() function can be replaced by an operator overloading function [which has identical code]:
void operator+=(cx n) { real += n.real; imag += n.imag; }
The result is handling of complex numbers in a very natural way:
cx x(1.0, 2.0), y(3.0, 4.0); x += y;
These features of C++ can certainly help clarify code, particularly the operator overloading. However, a word of warning. It is essential to maintain the intuitive functionality of the operator, as I have here. The += does exactly what the reader of the code would expect. Many years ago, when I was first learning C++, I read a book that demonstrated the overloading of the + operator, which would result in a statement like this:
x + y;
This would add y to x. Go figure.