C++ on Small-Footprint Microcontrollers
It seems to me people consistently shy away from, or rather vehemently oppose the use of, C++ on microcontrollers, but I can't for the life of me figure out why. If you stay away from large C++ libraries (e.g. STL) and you don't try to use complicated features like RTTI or exception handling, is there really any noticeable difference between C vs C++? Does virtual inheritance have a huge impact on complexity or footprint? I would think it'd be a little extra memory, but most of the complexity would be handled by the compiler, but then again I don't know a lot about that dark magic. I just don't understand why people are pretty adamant about using C, except maybe for the few architectures for which there aren't C++ compilers (if there are any). It seems the benefits of modularization and templates would be a no-brainer, even if you couldn't use your cin or cout.
I ask because I'm doing some research for some hobby projects I'd like to work on. Ideally, I'd like to work with C++ strictly for the capability to nicely modularize things, vs. C's "SomeClass_SomeMethod( struct object* this ... )" approach to "object orientedness". (I'd much prefer object Pascal for these projects, but alas support for that language isn't exactly stellar...) I would rather avoid moving to a much more capable microprocessor because A. for the projects I'm doing, I don't need tons of reso开发者_如何学Pythonurces.. I'm not planning on writing 60 state Kalman filters or encoding 1080p video B. (the real kicker) I'd like to use processors available in DIP and QFP packages. I'd like the ability to prototype without soldering or baking anything in my toaster oven.
Any thoughts?
In C++ you essentially only pay for what you use over and above what would otherwise be C compilable code, and some of the extras are cost free.
The biggest issue with some C++ compilers for small targets is the completeness of available C++ implementations or the availability of a C++ compiler at all.
EETimes/Embedded.com has run a number of articles on the subject over the years:
- Better even at the lowest levels - Dan Saks
- Embedded C++ Yields Faster Smaller Code - John Carbone
- Why C++ is a viable alternative to C in embedded systems design - Fergus Bolger
- Poor reasons for rejecting C++ - Dan Saks
- Using C++ Efficiently in Embedded Applications - Mentor Graphics/Cesar A. Quiroz
- The Inefficiency of C++ , Fact or Fiction? - IAR Systems/Anders Lundgren
The point most of these articles make is that you should not necessarily use all of C++ in an embedded system and they measure or explain the cost in terms of memory, speed, and determinism of various features. What parts you use will depend on the nature of your application (whether it has real-time constraints for example), and the available resources and performance of your target platform.
The C++ committee wrote a (free) technical report on this subject.
Of course it varies a lot.
I wouldn't use virtual inheritance on a "small" MCU. I wouldn't even use a heap at all.
The features of C++ that seem most attractive in that space are namespaces (to share software components between programs for networked MCUs), templates (e.g., to parameterize protocols over I/O ports), and general semantic improvements like static_cast
and less coarse integral promotion.
But, at least in my brief foray into professional embedded, a suitable C++ compiler simply didn't exist, and the crappy one that was available cost thousands a year.
GCC is the most capable, widely-available C++ compiler available for embedded platforms. However, its platform support is very uneven. If you have unlimited resources, EDG advertises that they will bring support superior to Comeau to "your" embedded platform.
C++ people constantly ask "why are you using C and not C++". I would like to know why I should be using C++ and not C.
First of all, one must come to the realization that these two languages are both ancient, and they both have horrible syntax. The debate often seems to be focused around "you should use C++, because C++ is modern and C is old". In reality, the debate is about one's favourite flavour of dinosaur meat. Instead of demanding a modern language suitable for embedded, people preach C++, which never was anything but a weird temporary hybrid language with C compatibility, in wait for some better language to be invented.
Second, there is a myth saying that C++ is object-oriented and C is not. The buzzword object-orientation boils down to three things:
- 1) Modular design with autonomous objects, that aren't tightly coupled to anything else. This is a very important attribute of any program.
- 2) Private encapsulation of data and reduced scope of data. This is a rather important attribute of any program.
- 3) Polymorphism of classes: classes that inherit other classes and behave differently when inherited. Polymorphism is quite useful, but far less so in small embedded systems.
1) can be fully achieved in both C and C++, it is a matter of program design rather than language syntax. And this is the most important OO attribute by far! Unfortunately, there is nothing in any language standard telling you how to design your program. There is nothing in C++ that will automatically lead to a better modular design, it is all in the hands of the programmer.
2) can be achieved in both C and C++. Both languages have reduced scope of data. In C, private encapsulation is done through somewhat horrible syntax with the static keyword on file scope variables. In C++, it is done more elegantly with private/protected.
3) can be achieved in both C and C++. Both languages have horrible syntax for this. In C you would fiddle around with structs and function interfaces to achieve it. In C++, you can do it in less horrible ways through heritage and making functions "virtual". The C++ syntax and the needed implementation is still one big mess however, although a bit better than the C way.
Neither language will give you OO-related things in pretty, elegant ways. What C++ gains from somewhat less icky syntax, it loses when you start wading through undefined/unspecified/implementation-defined behavior.
It would seem that the whole OO argument isn't a big deal, C++ is not a huge improvement when it comes to OO. Then what else is there in C++ that I would need in my embedded system? One thing stands out: standardized inline assembler syntax. This is perhaps the biggest advantage C++ has over C, for embedded systems.
Apart from that, excpetions, STL, templates, RTTI, overator overloading, function overloading etc etc, are all more or less useless features one can live without.
Then in the end, reality comes to slap you in the face: there are extremely few, if any, embedded compilers that have managed to fully implement C++ according to the standard.
is there really any noticeable difference between C vs C++?
In my experience there is a big difference in the usage of RAM.
For example: I am currently working on C++ for an ARM uC with 512KB FALSH and 64KB of RAM. RAM usage should be less than 30kB but is twice that because every const ends up in RAM. That is because it is nearly impossible (at least with GCC and ARM targets) to convince the compiler to leave const class members in FLASH. The only way to achive this is by using constructor-less classes, declaring all const members public and using aggregate initializer lists.
To make things worse, C++ does not allow members to be named in the initializer list like you can do in plain C:
struct St { int b; int a[3]; }; static const struct St st_array[2] = { [1] = { .a = {1,2,3,}, .b = 10, }, // deliberately disordered to [0] = { .b = 8, .a = { 4,5,6,}, }, // illustate the value of names. };
All C-compilers will put these constants into the "constant data" segment (in FLASH).
In C++ you would have to do this:
class ClassA // cannot have constructor or destructor { public: // const data cannot be private for aggregate initialization const int b; const int a[3]; private: int priv_fn(int i); public: int pub_fn(); }; static ClassA classA_array[2] = { { 3, { 8, 9,10,}, }, // aggregate initialization { 4, { 9,10,11,}, }, // better get the order right!!! };
Depending on your compiler, even this may not guarantee that the constants stay in FLASH.
And yes I know, with C++0x you can use initializer lists with the constructor and that is what I am doing, but the moment you have a constructor which gets called at runtime, all initializations become dynamic.
The technical report (thanks MSalters) confirms this:
7.1.2 Constructors and ROMable Objects In general, const objects of classes with constructors must be dynamically initialized. However, in some cases compile-time initialization could be performed if static analysis ...
The bottom line is that such static analysis is not done by any compiler I have available and if I have to limit myself to constructor-less classes with public consts and without initializer naming then I might as well write in plain (and object-oriented) C.
For "small footprint" where I would be concerned is code bloat. If your code needs to reside in a small piece of hardware, an instance of the template class
std::vector<int>
has its own set of instructions, seperate from
std::vector<double>
So every time you create a new kind of vector, the compiler effectively copy-pastes the code to create the new class, with its own set of functions, duplicating every instruction. If you have constraints on the amount of memory to store instructions, this could become problematic very fast. Its become problematic for people on non Embedded systems.
In terms of runtime performance, though, I think you don't have much to worry about. In some cases, such as sorting, C++ outperforms C.
精彩评论