C++ in Embedded Systems: Myth and Reality by Dominic Herity Listings Listing 1 Function name overloading. // C++ function name overload example void foo(int i) { // ... } void foo(char* s) { // ... } void main() { foo(1); foo(³Hello world²); } Listing 2 Function name overloading in C. /* C substitute for */ /* function name overload */ void foo_int(int i) { /* ... */ } void foo_charstar(char* s) { /* ... */ } void main() { foo_int(1); foo_charstar(³Hello world²); } Listing 3 A trivial class with member function. // A trivial class class foo { private: int x; public: void bar(); }; void foo::bar() { x = 0; } Listing 4 C substitute for trivial class with member function. /* C substitute for trivial class foo */ struct foo { int x; }; void bar_foo(struct foo* this) { this->x = 0; } Listing 5 A simple string class featuring constructors, destructors, operator overloading, new, and delete. // A simplified string class #include #include using namespace std; class String { private: char* data; unsigned len; public: String(); ~String(); unsigned length() const; String& operator=(const char* s); }; inline unsigned String::length() const { return len; }; String::String() { len = 0; data = 0; } String::~String() { if (data != 0) delete [] data; } String& String::operator=(const char* s) { len = strlen(s); data = new char [ len+1 ]; if (data == 0) len = 0; else strcpy(data, s); return *this; } void main() { String s; s = ³Hello world²; cout << s.length(); } Listing 6 C substitute for simple string class. /* C substitute for simplified string class */ #include #include #include struct String { char* data; unsigned len; }; #define length_String(s) ((s)->len) void StringConstructor(String* this) { this->len = 0; this->data = 0; } void StringDestructor(String* this) { if (this->data != 0) free(this->data); } String operatorEquals_String_const_char_star( String* this, const char* s) { this->len = strlen(s); this->data = (char*) malloc( (this->len+1) * sizeof(char)); /* If char had a constructor, */ /* it would be have to be */ /* called here. */ if (this->data == 0) this->len = 0; else strcpy(this->data, s); return *this; } FILE* operatorShiftLeft_ostream_unsigned(FILE*, unsigned); void main() { String s; StringConstructor(&s); operatorEquals_String_const_char_star( &s, ³Hello world²); operatorShiftLeft_ostream_unsigned(stdout, length_String(&s)); StringDestructor(&s); } Listing 7 Inheritance. // Simple example of inheritance class A { public: A(); int f(); private: int value; }; A::A() { value = 1; } int A::f() { return value; } class B : public A { private: int secondValue; public: B(); int g(); }; B::B() { secondValue = 2; } int B::g() { return secondValue; } void main() { B b; b.f(); b.g(); } Listing 8 C substitute for inheritance. /* C Substitute for inheritance */ struct A { int value; }; void AConstructor(struct A* this) { this->value = 1; } int f_A(struct A* this) { return this->value; } struct B { struct A a; int secondValue; }; void BConstructor(struct B* this) { AConstructor(&this->a); this->secondValue = 2; } int g_B(struct B* this) { return this->secondValue; } void main() { B b; BConstructor(&b); f_A ((struct A*)&b); g_B (&b); } Listing 9 Virtual functions. // Classes with virtual functions class A { private: int value; public: A(); virtual int f(); }; A::A() { value = 0; } int A::f() { return 0; } class B : public A { public: B(); virtual int f(); }; B::B() { } int B::f() { return 1; } void main() { B b; A* aPtr = &b; a->f(); } Listing 10 C substitute for virtual functions. /* C substitute for virtual functions */ struct A { void **vTable; int value; }; int f_A(struct A* this); void* vTable_A[] = { (void*) &f_A }; void AConstructor(struct A* this) { this->vTable = vTable_A; this->value = 1; } int f_A(struct A* this) { return 0; } struct B { A a; }; int f_B(struct B* this); void* vTable_B[] = { (void*) &f_B }; void BConstructor(struct B* this) { AConstructor((struct A*) this); this->a.vTable = vTable_B; } int f_B(struct B* this) { return 1; } void main() { struct B b; struct A* aPtr; BConstructor(&b); typedef void (*f_A_Type)(struct A*); aPtr = (struct A*) &b; ((f_A_Type)aPtr->vTable[0]) (aPtr); } Listing 11 A C++ template. // Sample template class template class A { private: T value; public: A(T); T f(); }; template A::A(T initial) { value = initial; } template T A::f() { return value; } void main() { A a(1); a.f(); } Listing 12 A C ³template.² /* C approximation of template class */ #define A(T) \ struct A_##T \ { \ T value; \ }; \ \ void AConstructor_##T(A_##T* this, \ T initial) \ { \ (this)->value = initial; \ } \ \ T A_f_##T(A_##T* this) \ { \ return (this)->value; \ } A(int) /* Macro expands to Œclassı A_int */ void main() { A_int a; AConstructor_int(&a, 1); A_f_int(&a); } Listing 13 A C++ exception example. / C++ Exception example #include using namespace std; int factorial(int n) throw(const char*) { if (n<0) throw ³Negative Argument to factorial²; if (n>0) return n*factorial(n-1); return 1; } void main() { try { int n = factorial(10); cout << ³factorial(10)=² << n; } catch (const char* s) { cout << ³factorial threw exception : ³ << s << ³\n²; } } Listing 14 A C ³exception² example. /* C approximation of exception handling */ #include #include jmp_buf ConstCharStarException; const char* ConstCharStarExceptionValue; int factorial(int n) { if (n<0) { ConstCharStarExceptionValue = ³Negative Argument to factorial²; longjmp(ConstCharStarException, 0); } if (n>0) return n*factorial(n-1); return 1; } void main() { if (setjmp(ConstCharStarException)==0) { int n = factorial(10); printf(³factorial(10)=%d², n); } else { printf( ³factorial threw exception : %s\n², ConstCharStarExceptionValue); } } Listing 15 A C ROMable dictionary. /* A C ROMable dictionary */ #include typedef struct { const char* englishWord; const char* foreignWord; } DictEntry; const static DictEntry germanDict[] = { {³yes², ³ja²}, {³no², ³nein²}, {NULL, NULL} }; const static DictEntry frenchDict[] = { {³yes², ³oui²}, {³no², ³non²}, {NULL, NULL} }; const char* FromEnglish( const DictEntry* dict, const char* english); const char* ToEnglish( const DictEntry* dict, const char* foreign); /* ... */ void main() { puts(FromEnglish(frenchDict, ³yes²)); } Listing 16 A C++ ROMable dictionary NOT! // NOT a ROMable dictionary in C++ #include using namespace std; class Dict { public: Dict(); const char* fromEnglish( const char* english) const; const char* toEnglish( const char* foreign) const; private: enum { DictSize = 3 }; struct { const char* english; const char* foreign; } table[DictSize]; }; // *** Following wonıt compile *** const static Dict germanDict = { { {³yes², ³ja²}, {³no², ³nein²}, {NULL, NULL} } }; // *** Following wonıt compile *** const static Dict frenchDict = { { {³yes², ³oui²}, {³no², ³non²}, {NULL, NULL} } }; // ... void main() { cout << germanDict.fromEnglish(³yes²); } Listing 17 A C++ ROMable corruptable dictionary. // A ROMable dictionary in C++, // but with poor encapsulation #include using namespace std; class Dict { public: const char* fromEnglish( const char* english) const; const char* toEnglish( const char* foreign) const; // PLEASE donıt access anything in the class // below this comment. // PLEASE donıt create your own instances // of this class. enum { DictSize = 3 }; struct { const char* english; const char* foreign; } table[DictSize]; }; const static Dict germanDict = { { {³yes², ³ja²}, {³no², ³nein²}, {NULL, NULL} } }; const static Dict frenchDict = { { {³yes², ³oui²}, {³no², ³non²}, {NULL, NULL} } }; // ... void main() { cout << germanDict.fromEnglish(³yes²); } Listing 18 A clean C++ ROMable dictionary. #include using namespace std; class Dict { public: typedef enum { german, french } Language; Dict(Language lang); const char* fromEnglish( const char* english) const; const char* toEnglish( const char* foreign) const; private: class DictTable { public: const char* fromEnglish( const char* english) const; const char* toEnglish( const char* foreign) const; enum { DictSize = 3 }; struct { const char* english; const char* foreign; } table[DictSize]; }; const static DictTable DictTables[]; Language myLanguage; }; const Dict::DictTable Dict::DictTables[]= { { { {³yes², ³ja²}, {³no², ³nein²}, {NULL, NULL} } }, { { {³yes², ³oui²}, {³no², ³non²}, {NULL, NULL} } } }; // ... void main() { Dict germanDict (Dict::german); cout << germanDict.fromEnglish(³yes²); } Listing 19 C reality check. /* Reality check - */ /* some things to avoid in C */ #include #include void main() { char s[] = ³Hello world²; unsigned i; int var =1.0; printf(s); for (i=0; i < strlen(s); i++) { /* ... */ } }