Guidelines for using C++ as an alternative to C in embedded designs: Part 1

April 11, 2008

Object Oriented Features
C++ is often described as an object oriented language, but this is not strictly true. It is really a procedural language (like C) with some object oriented capabilities.

The key language feature is the concept of a class. A class is very similar to a structure in C, but has some important differences and enhancements:

1) A class is defined using the keyword class.

2) A class may contain code as well as data (not just pointers to functions)

3) Class members may be declared as private or public, enabling key functionality to be hidden (encapsulated)

4) A class is, in effect, a new data type with the name of the declared class; the data and possible operations on that data are defined

5) Operators may be defined (overloaded) to manipulate the data in a class, which leads to readable, intuitive code

6) Member functions may be included that are automatically called when an object is created and destroyed (constructors and destructors)

7) One class may be derived from another, inheriting all of its characteristics, which may be augmented or replaced

Templates
A much-vaunted feature of C++ is templates. This concept may be applied to function or class definitions. The idea is simple: the programmer can define the complete structure and logic of a class/function, but leave the specification of data types (for parameters and internal variables) open.

This acts as a "recipe" for the compiler to generate code/data when the programmer instantiates a template (and indicates which data types are required).

Here is a simple example of a function template:

        template void swap(X& x, X& y)
        {
                X temp;
                temp = x;
                x = y;
                y = temp;
}

This might be utilized like this:

        int i, j;
        float a, b;
        ...
        swap(a, b); // instantiation #1
        wap(i, j); // instantiation #2

Templates provide all programmers " desktop and embedded alike " with a very useful capability to create highly reusable code. But embedded developers always want to know the "cost" " what is the overhead incurred by the use of templates?

In theory, no overhead would be anticipated, as a template does not itself generate code " code is only created by the compiler when required. But this is the cause of a problem: compilers only process one module at a time, so the template instantiations are on a per-module basis.

The result of this is the same code " i.e. a template instantiated with an identical set of data types " might be generated in numerous modules of the application. This may increase the memory footprint very significantly. This may be of minimal concern to the desktop programmer, but is likely to be of great importance to the embedded system developer.

A possible solution to this problem " apart from simply understanding what is happening " is to have tools which are optimized for embedded work. One approach is to have a linker which can take "hints" from the compiler and eliminate redundant (copies of) code.

Exception Handling
In almost any kind of software there exists the possibility for error conditions to occur, which may be detected by the software. Often, this requires some kind of "emergency exit" to some code to deal with the error gracefully.

Unfortunately, structured programming languages (like C, C++ etc.) do not conveniently handle such a possibility. The C++ Exception Handling System (EHS) was created to address this problem.

The EHS is manifest in three additional C++ keywords: try, throw and catch. A try block is used to control when exception handling is active. A throw statement is used to instigate the processing of an error (exception). And a catch block " of which there may be many, each identified by an object type " contains the code to process the error.

Here is a simplistic example which shows how the EHS syntax works:

        void scopy(char* str)
        {
                if (sizeof(store)+1 < strlen(str))
                        throw -1;
                strcpy(store, str);
        }

        void get_string()
        {
                char buff[100];

                cin >> buff;
                scopy(buff);
        }

        main()
        {
                try
        {
                    ...
                    get_string();
                    ...
                }
        }

        catch (int err)
        {
                cout << "String too long!";
        }

Although the EHS simplifies the coding required to deal with emergency situations, it does come with a cost: extra code is generated to enable throw statements to work correctly. An embedded developer is always wary of extra overheads, so the size of this extra code should be monitored.

There are two additional points about the EHS that embedded developers need to appreciate:

First, since the compiler has no way to know whether a particular piece of code will be called from within a try block, the extra code will be generated for all the application program modules. What is worse is that some compilers have EHS enabled by default and it is the programmer's responsibility to turn it off. So, if the EHS is not being used, it is essential to check the options on the compiler to ensure that no overhead is being incurred.

Second, the EHS is designed to facilitate a selection of different responses to a wide variety of error conditions. This makes complete sense for desktop applications. However, many embedded applications have quite simple error handling needs.

Often, a system reset is performed if a "difficult" error is detected, as this is the best way to get back to a stable operating state. It may quite reasonably be concluded that the EHS would be overkill under these circumstances. However, there are two ways to use it with lower overhead, which may tip the balance in its favor:

* If no matching catch statement is found when a throw is effected, a library function terminate() is called. This function could be replaced by a routine to perform a system reset.

* Just a generic catch handler may be provided, using this notation:

            catch (...)

This will catch exceptions of any type and results in a measurably lower code overhead.

< Previous
Page 2 of 4
Next >

Loading comments...

Most Commented

  • Currently no items

Parts Search Datasheets.com

KNOWLEDGE CENTER