Colin Walls
EE Times
Specialized languages have been developed to address the unique requirements of embedded developers, but none have found universal acceptance
This all started early last year, when I received an email from Clive (Max) Maxfield. He was hosting and moderating a session at Design West, and he asked me whether I would care to participate. The session was called "10 Languages in 45 Minutes." The idea was that there would be 10 speakers, each of whom would have four minutes to talk about a specific language of relevance to embedded system developers. The additional five minutes would be for Max's introduction and closing statements. He asked me to cover C++, and I was more than happy to accept this invitation.
The session went very well. We had a very good-sized audience, which was pleasing, particularly as we were starting at 8:30 a.m. After a brief introduction from Max, the speakers made their pitches, with Max running a timer to ensure fair play. The brisk pace made for a very dynamic session, and I believe that the audience enjoyed it. I certainly did.
After the session, I had an idea – why not write an article to share the concepts presented in this session with a wider audience? This is it, though I should note that I am confining myself to the five software programming languages. The other five were hardware description languages (HDLs); maybe we can return to consider those another day.
Embedded programming languages
In many ways, programming an embedded system is not too dissimilar to coding for a desktop computer, but there are some key differences:
- On an embedded system, resources – memory and CPU power – are limited. By comparison, with desktop systems, it is commonly assumed that they have no limits.
- Embedded systems are commonly real-time.
- The number of operating systems in use on desktop computers is quite small. There are numerous options for embedded systems, including "bare metal" (i.e., no operating system at all).
- To the first approximation, the hardware of all PCs is identical. By comparison, every embedded system is different, so programming close to the hardware is more common.
In the early days of embedded systems, factor No. 1 – and, to some extent, Nos. 2 and 4 – resulted in most programming being performed using assembly language. This remains an option, but now assembly is used only when it is absolutely essential.
The needs of embedded developers are sufficiently special that it might be expected for specialized languages to have developed to address their unique requirements. There are examples of languages that have been designed from the ground up for embedded applications (e.g., PL/M, Forth, Ada), but they have not found universal acceptance.
C
C was designed in the 1970s by Dennis Ritchie at AT&T Bell Labs. The language was based on an earlier attempt to develop a high-level language called B that had the benefits of assembly. This, in turn, had started out as BCPL back in Cambridge, England. The original reference book, The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie, was published in 1978. Full standardization (by ANSI) took another 10 years, and there have been a number of iterations since.
Though never designed or intended for embedded use, C remains the most widely used embedded programming language, with compilers available for almost every microprocessor, microcontroller, and processor core on the market.
Even though C is a structured language, it offers a great deal of flexibility, enabling code to be written that is quite readable, but with obfuscation a readily available option.
Here is an example of quite well laid-out C code.
int x, y, z;
for (x = 0; x < 4; x++)
{
z = strlen(bullets[x]);
for (y = 0; y < z; y++)
{
blab(bullets[x][y]);
}
}
The following style is slightly more compact but still valid.
for (int x = 0; x < 4; x++) {
for (int y = 0; y < strlen(bullets[x]); y++) {
blab(bullets[x][y]);
}
}
The following is also valid, but it's also a good example of unreadable code.
for(int x=0;x<4;x++) for(int y=0;ystrlen(bullets[x];y++) blab(bullets[x][y]);
Notwithstanding its challenges, C syntax has been the basis for a number of other languages (as we shall see). Apart from needing care with layout, C has a number of other "flexibilities" that can lead to problems:
- Pointers are powerful but can easily lead to confusion.
- The language is weakly typed, thereby facilitating accidental conversions, which can very easily lead to subtle errors.
- Dynamic memory facilities are quite primitive and not well suited to real-time systems.
Many C users value the language's strengths and have taken action to mitigate its weaknesses. This has resulted in a number of approaches to constrain the use of C to avoid the pitfalls. Probably the best-known example is MISRA C, which started out in the automotive world but is finding favor elsewhere.
C++
Though object oriented programming (OOP) was not a new idea (at least one such language existed in the mid-1960s), it really became fashionable in the 1980s. As a result, a number of languages appeared, several of them based on C. This is probably a good time to look at the "family tree" of programming languages, shown below.
The language family tree. |
A number of C-derived OOP languages have survived, but the one that really took hold and is popular for embedded development is C++, which was designed by Bjarne Stroustrup at Bell Labs.
One of the key factors in the success of C++ was its initial implementation. Instead of writing a conventional compiler, Stoustrup wrote a pre-processor – "cfront" – that translated C++ into standard C. This meant that the new language was ready for use just about anywhere a C compiler was available. Nowadays, special C++ compilers are very common, but the pre-processor approach gave the language a strong kickstart.
The point of OOP is to aid the development of larger software projects. This is a challenge increasingly experienced by embedded developers. Using an OOP approach can enable each programmer to focus on his or her own area of expertise without necessarily understanding every aspect of the whole application.
C++ can be used in two ways: It can simply be regarded as "a better C language" on the basis of a number of facilities and constructs that benefit programmers, or it can be used as a true object oriented language. The latter approach can be very useful for embedded applications, since it enables the encapsulation of specialist code, such as device access.
A key feature of C++ is the notion of a class. A class in C++ is somewhat like a structure in C, with some specific differences:
- A class can contain code as well as data.
- Code and data can be hidden from users of the class.
- Special functions may be included in a class to enable operators to define that function with instances of the class.
- A class is essentially a new data type; instances of the class are called "objects."
- The syntax of object definition is simpler than structure instances; just the class name needs to be quoted.
A simple example of a C++ class definition is as follows.
class woport
{
int shadow;
int* address;
public:
woport(long);
~woport();
void operator|=(int);
void operator&=(int);
}
Note how the object (or variable, if you like) "out" is declared in a very conventional way and used naturally with familiar operators. The writer of this "main()" function does not need access to the source code of the functions in the "woport" class.
Of course, C++ has its downsides. Without care, the language can exert a greater load on resources than might be anticipated. Modern tools help up avoid this problem and aid in the development of optimum code. Historically, many "embedded" toolkits did not sufficiently address the resource utilization needs of the embedded developers. As a result, many bad experiences tarnished the language's reputation in many quarters. This probably explains why, though popular, the migration from C to C++ has been slower than anticipated.
Java
Java was developed by James Gosling at Sun Microsystems (now part of Oracle Corp.) and released in 1995. Gosling's original concept was the creation of a robust language that could be used to write portable embedded applications. Over the years, Java has found considerable success as a means of running a program (an "applet") in a browser. This enabled developers to run sophisticated applications, hosted on web pages, that would run on any browser on any platform.
The official emblem of the language Java. |
More recently, Java has been used in ways more attuned to its original concept of facilitating the incorporation of post-deployment applications ("apps") into embedded devices. This is common practice with the Android operating system.
Java has conventionally been implemented using an interpreter. A Java compiler converts the source code into "bytecodes," which are a very compact representation of the logic. The interpreter – the Java virtual machine – reads and executes the bytecodes. Modern Java implementations may also offer conventional compilation or just-in-time (JIT) compilation as alternatives.
Java is an object oriented language with syntax based on C, borrowing functionality and further syntax from a number of other languages (like C++) that added OO capabilities to C. Unlike C++, Java is a true OO language, as opposed to a procedural language with OO capabilities.
There are no pointers in Java; this reduces programming errors. Multi-threading is intrinsic in the language, and dynamic memory allocation is well developed with sophisticated garbage collection.
An example of some Java code:
BitSet mask = new BitSet();
mask. set(cpuId);
AffinitySet as = AffinitySet.generate (mask);
AffinitySet.set(as, thread);
Java is only really applicable to 32-bit or 64-bit devices. The runtime system needs a reasonable amount of CPU power. However, with 32-bit microcontrollers becoming extremely cheap, Java's reach is extending.
Java was not originally intended for real-time applications. However, real-time and safety-critical specifications have been developed in recent years.
Java is very commonly taught in schools and colleges, because it provides a good basis for sound programming practice. This has resulted in a very large programming community, the availability of numerous libraries, and a wide choice of developer tools.
JavaScript
JavaScript was developed at Netscape in 1995. Its name is confusing, because it has no real connection with Java. The selection of nomenclature was a marketing matter.
Unofficial JavaScript logo. |
The language has a C-based syntax, but it also has a number of features that are different from other C derivative languages. Typing is dynamic – a value has a type, but a variable does not. It is an object oriented language; objects are associative arrays (and vice versa). Instead of classes, JavaScript is coded in terms of prototypes. There are numerous libraries available, many of which deal with browser and user interface issues.
Programming in JavaScript can be very productive – much is achievable with limited knowledge. This makes the language attractive to nonprogrammers and also explains the plethora of bad JavaScript code.
JavaScript was originally intended as a means to give programmatic capabilities to web pages, and it is now almost ubiquitous. Any modern-style web page uses JavaScript. It has been called the "Assembly Language of the Web" (presumably by someone who was unfamiliar with assembly programming). Furthermore, JavaScript is at the heart of HTML 5, which is gaining widespread adoption.
The source code is included in a web page definition. This is executed by means of a highly optimized just-in-time compiler built into the browser. Amazingly complex web applications have been implemented in JavaScript. In the embedded systems context, JavaScript is particularly interesting for cross-platform application development and the definition of user interfaces.
An example of JavaScript code that has been embedded in an HTML file is shown below.
script
function fact(x)
{
if (x == 0)
return 1;
return x * fact(x - 1);
}
alert(fact(4));
/script
Python
Another language that first appeared in the early 1990s – Python – was created by Guido van Rossum. It is thought of as a scripting language, but it is powerful enough for much more sophisticated programming applications.
Python logo. |
Python borrows some syntactic elements from C but is less C-like than the other languages discussed above. In particular, white space is significant to program structure, which tends to lead to more intrinsically readable code.
Below we see an example of Python code.
def remove_dupes(mylist):
mylist.sort()
last = mylist[-l]
for i in range(len(mylist)-2, -1, -1):
if last == mylist[i]:
del mylist[i]
else:
last = mylist[i]
The language is broadly object oriented (everything is an object), but it also supports procedural and functional programming styles. Typing is strong but dynamic, with support for lists, dictionaries, etc. The language is interpreted – the source is compiled to bytecodes (like Java) – and executed by a virtual machine.
The Pythonic philosophy is as follows:
- Beautiful is better than ugly.
- Explicit is better than implicit.
- Simple is better than complex.
- Complex is better than complicated.
- Readability counts.
Python has been widely used in embedded applications and has many more potential uses where its unique style is beneficial. The implementation is readily portable, so the language can be used just about anywhere. Not so long ago, the developers of the low-cost, single-board Raspberry Pi computer selected Python as its primary programming language.
Conclusions and acknowledgements
It is easy to think of the embedded programming language as being C (along with C++), with a smattering of assembly language. However, there are other options where particular programming requirements demand a specific solution. It is interesting that the core C syntax, though often criticized, forms the basis for many other more recent languages.
I gratefully acknowledge the invaluable assistance I received with the planning and writing of this article from Clive Maxfield and the other Design West presenters/authors: Duane Benson, David Beberman, and Mark Guagenti.