Some more embedded software programming tips
Another in my occasional series of tips for embedded software developers. Sometimes my tips are just personal taste; on other occasions they are more like hard facts. But, of course, someone might disagree …
Three tips today:
Do not write while(something); – put the semicolon on the next line
Sometimes it is necessary to have a loop that just waits for something to occur and this most likely includes an empty statement. Although this is fine, some effort should be made to ensure that the code is readable and clear. Writing it like this is not very clear:
while (device_ready() == 0);
However, it take very little to make it better:
while (device_ready() == 0) // wait for response from interface ;
Some care is still needed, as this code might unintentionally become an infinite loop – if the device never responded. Whenever possible, include a timeout:
error_log = 0; timeout(100); // expect a response in 100ms while (device_ready() == 0) // wait for response from interface if (test_timeout()) { error_log = DEVICE_TIMEOUT; break; } if (error_log != 0) ...
In a real time system design, the word “dynamic” should ring alarm bells
In general English usage, the word “dynamic” has almost totally positive connotations. I would be delighted to have this adjective applied to me – though it is quite unlikely! In the context of software, the meaning is more specific: dynamic things are created and destroyed, as required. For example, dynamic memory can be allocated when it is required and de-allocated when the need has passed. This is very convenient, but comes at a cost. The management of dynamic memory tends to be non-deterministic – i.e. it does not behave in the predictable way that is required to build a real-time system. Additionally, failure modes can be problematic. A while ago, I presented a webinar on this topic and the recording is still available.
The best solution is to use an real-time operating system, like our Nucleus RTOS product, that provides memory allocation facilities that are compatible with the needs of a real-time application.
In C++, overloaded functions have zero impact on code size or performance
At first sight, being able to have two different functions with the same name sounds confusing, but it can actually be used to write clear code. C++ offers two facilities along these lines: templates and overloaded functions. Templates are a newer language facility and, whilst they can be useful, there are some challenges with their use. Overloaded functions are simpler and have been in the C++ language since the start. Indeed the concept of an overloaded function goes back to the Fortran language in the mid-1960s.
If you need to perform similar operations on different types of data, overloaded functions are a very clear way to code the functionality. All you need to do is ensure that each function has a different combination of parameter types/numbers. So, you can write code like this:
int max(int, int); int max(int, int, int); float max(float, float);
Each max() function is different and the compiler will use the appropriate one according to the provided parameters. This works because C++ “mangles” function names to include parameter number and type information. There is absolutely no “cost” for this facility – no extra code or execution time penalty.
If you have any handy tips that you might like to share, please email or contact me via social media.
Comments
Leave a Reply
You must be logged in to post a comment.
Hi,
@ Do not write while(something); – put the semicolon on the next line
I’m advocating for using {} braces all over the place.
So I would write the loop like this:
while (device_ready() == 0) // wait for response from interface
{
// Intentionally empty.
}
I’m taking this to the extreme, but then I think the readability is taken to the extreme too 🙂
—
Best regards,
Andrzej Telszewski
@Andrzej – On reflection, I think that I agree with you. Thanks.
Thank you for this article.