Another 5 embedded software programming tips
Today is another in my occasional series of posts that document a few useful tips for embedded software developers. I received some good feedback from the last posting in the series, so I hope that these tips are equally useful …
Only use [ ] operator(s) with an array; not with a pointer.
In C/C++ an array is accessed thus:
x = myarray;
Two things are not immediately obvious. First, an array name is just a [constant] pointer. Second, [ ] are just operators that are easier to read than conventional pointer notation. So, the above code could be rewritten like this:
x = *(myarray + 3);
In a similar fashion, the [ ] operators could be used with a normal pointer [variable]. However, for clarity, it is generally good practice to use [ ] with arrays and conventional pointer operators with pointers.
Do not create a USB custom class driver if you can possibly avoid it.
If you are designing a device with a USB interface, it is most likely that you will employ a commercial USB stack – maybe from your RTOS vendor. The part of the stack that characterizes a device – defines what kind of peripheral it is – is the class driver. If your design is totally custom, you may be tempted to create a custom class driver for it. Although that is an option, it may be better to consider whether your device resembles a standard item so that you can use an off-the-shelf class driver. Apart from being less work at this stage, using a standard target class driver frees you from the obligation to create a host driver or, in reality, maybe multiple host drivers [for Windows, Mac, Linux etc.].
If you want an empty while loop in C, put the semicolon on the next line by itself.
Sometimes it is reasonable to have an empty while loop that executes while you are waiting for something. Take care in the code layout so that the empty statement [just a semicolon] is not “lost”, thus:
while (!dataready() && !timeout()) ; //wait for device
not like this:
while (!dataready() && !timeout()); //wait for device
Think carefully before using malloc() in a real time system
Dynamic memory is a challenge in a real time system. This is for two main reasons: standard implementations of malloc() are not deterministic [i.e. execution time is not predictable] and allocation failure [maybe as a result of heap fragmentation] is hard to accommodate. Most RTOSes include facilities for memory allocation that avoid these issues.
Make sure C++ exception handling support is switched off in your compiler if you are not using EHS.
Exception handling is a very useful facility of the C++ language, as it can provide very straightforward way to code a mechanism to deal with unexpected [error] situations, without resorting to very complex conditional block structures or GOTOs. However, exception handling comes with an overhead – extra code is added to accommodate the checking and routing of an exception. This overhead may be acceptable and can be minimized, but many developers are not happy with any overhead, so choose not to use EHS. Many compilers turn exception handling ON by default and, hence, even if exception handling is not used, the extra code is there. Check to ensure that your compiler does not need EHS support to be switched OFF.
I prefer not to have empty loops whenever possible.
I normally write it in the following way:
bool b_dataready = false;
bool b_timeout = false;
while (!b_dataready && !b_timeout)
b_dataready = dataready();
b_timeout = timeout();
If, for whatever reason, the body of the loop has to be empty, then I write it like that:
while (!dataready() && !timeout())
Fair comment @Andrzej