Language Extensions
One of the big advantages of using a standardized language, like C++,
is that the code and the programmer's expertise are very portable. On
this basis, it would seem foolish to add extensions to a standardized
language, as this would lead to non-portability.
In an ideal world this would, indeed, be true. However, C++ (like C)
was designed for desktop computing application, not embedded. Embedded
developers are numerous, but still represent a small minority of C++
users. As a result, a small number of language extensions may be
considered useful and acceptable:
1) Many compilers, designed
for embedded use, include a feature to enable data to be packed, making
best use of memory by eliminating alignment bytes in arrays and
structures.
For this facility to be really effective, the programmer needs the
facility to turn it off for specific data structures, to increase speed
of access or provide format compatibility with some other system or
software. This override is usually implemented by the unpacked
extension keyword. A corresponding packed keyword may be available to
permit individual objects to be packed when the global option is
switched off.
2) Traditionally, interrupt
service routines (ISRs) were coded in assembly language for two
reasons: execution speed efficiency and context saving. Modern
compilers generate code which is certainly fast enough for an ISR, but
a regular function does not facilitate the full context save and
alternate return mechanism that is required. An additional keyword,
interrupt, is commonly provided to declare a function as being an ISR.
3) Sometimes the use of
assembly language is unavoidable. This is usually because a CPU feature
is inaccessible from C++ " enable/disable interrupts is a common
example.
Although there is always the option of calling a function written in
assembly language, the overhead may be reduced by being able to insert
the necessary lines of assembler code in line. Commonly the extension
keyword asm is available to facilitate the declaration of assembly
language pseudo-functions. (#pragma asm may also be a possibility.)
4) To embedded software
developers using C, the keyword volatile is essential, as it is common
to have variables that are shared between threads or represent I/O
devices. This keyword was not always implemented in early C++
compilers, but is obviously still required.
A Strategy for C to C++ Migration
The big advantage of the backwards compatibility between C++ and C is
that migration can be done gradually. A possible strategy is to apply a
three stage process:
1) Exploit reusability " write all new code in C++
2) Treat C as C++ " clean up existing C code
to comply with C++ requirements
3)
Start using C++ language features more widely
At some later point, the object oriented capabilities of C++ can be
exploited more fully.
Applying
Reusability. A potential incompatibility between C and C++ is
apparent at link time. A C++ compiler, as mentioned previously, will
mangle function names to incorporate information about the number and
type of parameters and return data type. This facilitates function
overloading and results in typesafe linkage. A C compiler will not do
this, so linking C and C++ modules would result in errors.
Fortunately, in C++ a mechanism is provided to work around this
problem: the linkage of a function may be declared as being compatible
with C using the extern "C" construct, thus:
#ifdef _cplusplus
extern "C"
{
#endif
extern void alpha(int a);
extern int beta(char *p, int b);
#ifdef _cplusplus
}
#endif