Some more embedded software programming tips
From time to time, I post a few programming tips that I hope are of use to embedded developers. Sometimes they are clearly beneficial; in others, there is controversy. Today’s selection is no exception …
Never use the fact that non-zero means true in C; always do an explicit test
Although it is not “dangerous” code – i.e. likely to produce undefined or unexpected results – code readability is impaired by using a more concise construct that applies this knowledge. For example, you might have a loop counting characters in a string:
i = 0; while (str[i]) i++;
This is valid code, but can be more clearly written:
i = 0; while (str[i] != 0) i++;
The resulting compiled code will be identical.
Incidentally, the code could also have been written like this:
i = 0; while (str[i++]) ;
But that would not be at all helpful.
If you place member function code inside a C++ class definition, this is a hint to the compiler to inline the code
A C++ class is very similar to a C struct, except that you can include functions as well as variables. This can be done in two ways. Commonly a reference to the function is included in the class definition and the function itself is defined elsewhere:
class stuff { int neg(int x); ... }; int stuff::neg(int x) { return (-x); }
Alternatively, the actual code for the function [usually only when the function is short] may be included inside the class:
class stuff { int neg(int x) { return (-x); }; ... };
Functionally, the results are identical, but putting the definition inside the class is a hint to the compiler [the same as using the inline keyword] that inlining the function code may be a good idea. The compiler is likely to ignore the hint if you compiler for size and a good compiler might figure this out for itself if you are compiling for speed.
printf() is not a debug tool
It has always been common practice, when developing code for desktop applications, to do certain types of debugging by simply outputting some information at strategic points in the program. In C, this would normally be done using the library function printf(). Although it may be argued that a sophisticated debug tool would make life easier, this approach is quite legitimate and can even have some advantages. However, for embedded applications, there are a variety of problems with using printf() as a debug tool:
- the printf() function is quite complex and, hence, large – this would be a problem if memory is limited
- many systems do not have a logical place for output to be sent
- in a real-time system, outputting debug data may affect the real-time integrity of the software
It is much better to use a built-for-purpose debugger or analysis tool.
If you are using an RTOS that does not support mailboxes, you can use a single entry queue
Any modern RTOS will have the means to implement inter-task communication and there may be a variety of options. A simple option may be a mailbox that allows a single data object to be sent from one task to another. The next level of complexity/flexibility would be a queue, where a number of data objects may be sent sent to a task for processing in a defined order. Many applications use both of these facilities. There are two special case scenarios:
- what if the RTOS does not support mailboxes?
- what if you only have a single mailbox [or very few], but use queues extensively?
For (1), you could use a single-entry queue to get the same result, albeit with a slightly greater overhead. For (2), you could consider doing the same thing, as this would eliminate the little-used mailbox support code [in a fully scalable RTOS, like Nucleus] and, thus, reduce the code size.