If you are reading this blog, you are probably knowledgeable about embedded software and, therefore, like me, you consider yourself proficient in C. C is still the dominant language for embedded work. I read an article recently which espoused the view that “real men program in C” – I rather liked that. It also suggested that, since relatively few new graduates know C, there is an increasing shortage of expertise. This is great news for us old hands.
However, we should not be complacent. I think that I know C quite well. After all, it is quite a small language, so getting a grip should not be hard. Even aspects of it that are specifically interesting to embedded developers [and there are quite a few] should not be too difficult to master. But sometimes it is possible to get caught out …
I will pose a question: what is the difference between ++i and i++?
I am sure that you know that both expressions result in the variable i being incremented, but the first expression yields the incremented value if i, whereas the second returns the value prior to incrementing. OK so far. But what if the expression result is discarded in a situation like this, for example:
for (i=0; i<5; i++)
Does it make any difference which form of the increment operator is used in this context? I would have said no. But then I had a conversation with one of our compiler team and now I know better.
Functionally, it makes no difference – ++i and i++ would both do the right thing. However, embedded developers are interested in more than just functionality – we are always interested in overheads. Think about what code might be compiled for each form of the expression. For ++i, the variable is simply incremented; for i++, the value needs to be stored somewhere and then the variable is incremented. This means that the post increment form needs some additional storage, which is an unwanted overhead.
Of course, for a simple integer, the overhead is quite small. But, if the variable were actually a complex C++ object, it might be a more serious matter.
It can be argued that a good compiler would observe that the expression result is not needed and this code would be optimized away. I sincerely hope that this would be the case. However, it is sloppy programming to just rely on compiler optimization to address the ignorance or laziness of the programmer.
If you have any other examples of subtle C features that are interesting to embedded developers, please email me.