|For novel ideas about building embedded systems (both hardware and firmware), join the 27,000+ engineers who subscribe to The Embedded Muse, a free biweekly newsletter. The Muse has no hype, no vendor PR. It takes just a few seconds (just enter your email, which is shared with absolutely no one) to subscribe.|
By Jack Ganssle
C, the most popular of all embedded languages, is an utter disaster, a bizarre hodgepodge meant to give the programmer far too much control over the computer. C++ isn't much better. The languages are designed to provide infinite flexibility, to let the developer do anything that can be done on the computer.
Don't get me wrong - I do like programming in C. Assembly is even more fun, which proves I'm some sort of computer gearhead, more fascinated with the system's internals than with actually delivering products.
But no language should allow stupid mistakes like buffer overruns or undetected array overflows.
Geodesic (http://www.geodesic.com/) claims 99% of all PC programs (most written in C and C++ of course) have memory leaks, all caused by poor use of malloc() and free(). Though these constructs are less common in the embedded world, an awful lot of firmware does use dynamic memory allocation. The language should simply not permit leaks; checks to guarantee memory integrity are essential. The cost is minimal. (Check out mem.txt at snippets.org, a simple bit of code you can link into your embedded app to detect all sorts of malloc()-related problems.)
Pointers are utterly unbounded in C. Want to dereference a null pointer? Go ahead! The language cares not a whit. Feel free to do any sort of math to any pointer. It's fun!
Here's a C hint that will improve your job security: embrace double indirection. Even better, try triple. Real programmers use quadruple. The only limit to the number of asterisks placed in front of a pointer is the size of one's cahones or how adventurous you feel.
Exception handlers are totally optional in C. Sure, they're nice to have, but the language itself does nothing force us to either write such handlers, or to write them in a way that's likely to work.
Even something as simple as integer math produces unexpected results. 20,000 + 20,000 is. a negative number. Is this cool or what!
C has no formatting rules. It's easy and usual to write source in astonishingly cryptic ways. Any language that allows utterly random use of the ENTER key (it's perfectly legit to hit ENTER after almost every character in C) is more an encryption tool than an aid to creating reliable and maintainable code.
No other language has an obfuscated code contest. Win by writing code that works but that's so convoluted no C expert can understand why. Most of the entries look like a two year old hit a few thousand random keys. And no, I'm not putting the URL of the contest here; these people are code terrorists who should be hunted down and shot.
A great programming language should encourage users to create perfect code. It must bound our options, limit our freedom, remove the degrees of freedom that lead to stupid bugs. Ada did this. It was so syntactically strict that the rule of thumb was "if you can make the damn thing compile it'll probably work." The language itself served as a straitjacket that led to reliable firmware. So of course Ada more or less failed, now barely appearing as a blip on language surveys.
Other options exist. The MISRA folks (www.misra.org.uk) have a set of rules that limits use of dangerous C constructs. Cyclone (http://www.research.att.com/projects/cyclone/) is a sort of C dialect that leads to more correct code. Neither has much market presence.
C sucks. Sure it's fun and efficient. Debugging is much more of a kick than taming an angry syntax checker that insists on correctness. But it's time for the entire firmware community to either embrace a restrictive dialect of the language, or to adopt an Ada-like lingo that implicitly leads to correct code.
What do you think?