Dave Nadler wrote:> On Wed, 15 Oct 2014 19:21:11 +0200, Wouter van Ooijen wrote: >>PS I am (in the context of this question) NOT interested in >>- whether a reason is valid (please start a different thread for >>discussing this, I'll surely join in). > > !!! Availability of skilled C++ developers !!!+1 What helps me most is that I am able to think like a compiler, because I wrote half of one during university. Few people can do that (and it isn't a skill that embedded recruiters have on their list). So while most people can get a program correct after a while, only few can make it efficient.> In the embedded space, think about how many folks > with lots of C++ on their resume could answer: > > 1) Give some examples where C++ can help you manage > low-level machine access easier than raw C.Your mileage will vary, but I found it very convenient to group things such as "SPI driver" in classes. Just the fact that I can then use spi.send(data); instead of freescale_mx35_spi_send(&spi, data); would be a good argument for me.> 2) In a small embedded system with no dynamic memory > (other than the stack): > > 2a) What language features will you not be able to use?This is a trick question, because if I don't have dynamic memory, I could simply write my own allocator. However, I will not be able to use most off-the-shelf components. If I have a whopping 4 kilobytes of heap, I don't want a std::vector or std::string that dutifully pre-allocates me 128 elements just to make future appends faster.> 2b) What special considerations will you expect when > creating a class?Depends on the compiler, but I would try to convince the compiler NOT to generate exception-handling code. This could mean not using destructors, and maybe even constructors. It still keeps language features like templates and classes-for-encapsulation, but the experience will be very different than for a "big" app.> 3) Give an example where using C++ a template can generate > more efficient code than typical C coding.C++ templates can do compile-time polymorphy, that is, you use inline code where you would use function pointers in C. For a previous project, I was writing several drivers; some already existed in a prototype version in C. Drivers needed some sort of request/result queues. The C versions implemented these queues anew, every damn time, probably with a lot of cut & paste involved. First thing I did was to add a simple Queue template class and use it everywhere. My final source code was around half the size and much more maintainable than the C version; the object code was smaller by a few percent, too. Stefan
validity of ... reasons for preferring C over C++
Started by ●October 16, 2014
Reply by ●October 21, 20142014-10-21
Reply by ●October 21, 20142014-10-21
Paul Rubin <no.email@nospam.invalid> writes:> Dave Nadler <drn@nadler.com> writes: >> Sorry, I wasn't trying to pose a challenge; rather wondering if others >> have also had difficulty finding qualified help. > > There's lots of C++ programmers around and it's not THAT difficult a > language. I don't know your situation but around here, "difficulty > finding qualified help" often means "the help I need is available but I > don't want to pay market rates for it". > > That said, I thought your questions were interesting and I don't think > I'd currently pass a serious interview to select knowledgeable C++ > programmers. I've used enough C++ to get some specific tasks done and > studied it a bit out of PL geekery interest, but am not extensively > experienced with it. > >> We've used C++ on some pretty tiny machines, to good effect... > > Yes, Stroustrup keeps saying that it's perfectly well suited to the > small device space, and there's not a serious reason it shouldn't be, > if you program in a constrained style. > >> 4) Under what conditions could C++ add code or memory bloat? >> How can it help *reduce* code and memory bloat? > > The most notorious cause of C++ object code bloat is template > instantiation duplicating the same code all over the place for multiple > types. Of course the same thing would happen in C if you copied > functions all over, but in practice you'd tend to use some ad hoc > generic scheme with void* casts, function pointer callbacks for what > would be different template expansions, etc. But, I think the template > generic style only bloats the binary: it actually keeps source code more > concise and duplication-free (DRY principle). > > I'd say there's some runtime memory bloat from using STL containers > instead of specialized containers written around your specific data. I > guess this can be mitigated somewhat with custom allocators though I > haven't had to resort to that. There's also some memory bloat from the > idiomatic C++ style of passing large objects around by valueI have not seen that, c++ programs do tend to pass objects using *references*, and then the called functions operate on them using the same syntax "as if" the reference is the object itself. But really it is just a pointer being passed (as is usual in C also). Also c++11 has had a lot of work put into efficiently passing objects by move constructors and so forth, again it is just a pointer changing AIUI.> (i.e. copying them all over) though maybe that's less needed now that > shared_ptr (poor man's garbage collection) is used more. There are > now some hooks for actual GC as well, though I haven't used them yet. > > I do think using shared_ptr or GC can simplify programs a lot, getting > rid of a lot of complex and bug-prone manual storage management code, at > the expense of sometimes burning more memory than is strictly needed. I > like Rust's approach of combining good tracking of object ownership > (allowing just-in-time reclamation without GC in a lot of cases) and GC > for when you need it. I haven't yet used Rust but it's interesting. > > Similarly the use of libraries like STL and Boost simplify code by > supplying well-tested, fast implementations of standard data structures > that in C programs end up getting implemented half-assedly over and > over, differently in every program. That means smaller source code at > the cost of bigger object code, since those libraries pull in code for a > lot of features that you might not use. > > I'm hacking on a fairly small C++ program right now that compiles to a > 1.2MB binary, which seems ridiculous, like > 10x what it has any > business taking. So that's an example of object code bloat. On the > other hand, it's running on a 32GB machine so the 1.2MB is of no > consequence.I have been playing with embedded c++11, just some toy programs on ARM microcontroller development boards at the moment. The minimum footprint was only a few kB, it seems absolutely fine for even the smallest projects (that I would be interested in anyway). Even using some STL and vectors and strings and so forth seemed to work without doing anything too dramatic to the code size. -- John Devereux
Reply by ●October 21, 20142014-10-21
On Tuesday, October 21, 2014 1:12:15 PM UTC-4, Stefan Reuther wrote:> What helps me most is that I am able to think like a compiler, because I > wrote half of one during university. Few people can do that (and it > isn't a skill that embedded recruiters have on their list). So while > most people can get a program correct after a while, only few can make > it efficient.Um, you think like half a compiler ? ;-) Really, for C++ it is necessary to understand what happens under the hood (contrary to the definition of a good tool), but how the compiler works??> > 2) In a small embedded system with no dynamic memory > > (other than the stack): > > 2a) What language features will you not be able to use? > > This is a trick question, because if I don't have dynamic memory, I > could simply write my own allocator.No, it is not a trick question, and that is NOT the answer...> > 2b) What special considerations will you expect when > > creating a class? > > Depends on the compiler, but I would try to convince the compiler NOT to > generate exception-handling code.Why does it depend on the compiler??> This could mean not using destructors, > and maybe even constructors.No, no, no... What else?> For a previous project, I was writing several drivers; some already > existed in a prototype version in C. Drivers needed some sort of > request/result queues. The C versions implemented these queues anew, > every damn time, probably with a lot of cut & paste involved. First > thing I did was to add a simple Queue template class and use it > everywhere. My final source code was around half the size and much more > maintainable than the C version; the object code was smaller by a few > percent, too.A good example of C++ helping! However, some would argue you should have implemented the queue code once using void* (and maybe item size), then wrapped it with inlines using specific names/types for safety. Hopefully you wrote a unit test for your template before using it! Thanks for your thoughts, Best Regards, Dave
Reply by ●October 21, 20142014-10-21
On Monday, October 20, 2014 8:24:14 PM UTC-4, Paul Rubin wrote:> "difficulty finding qualified help" often means > "the help I need is available but I > don't want to pay market rates for it".Um, some of us know the true cost of finding, hiring, and integrating (assimilating?) the right staff. Thus we pay above market to keep them as net costs are lower...> I'm hacking on a fairly small C++ program right now that compiles to a > 1.2MB binary, which seems ridiculous, like > 10x what it has any > business taking. So that's an example of object code bloat.Often that's due to including iostreams; have you looked at the map to see what has been dragged in and why? Thanks for the thoughts, Best Regards, Dave
Reply by ●October 21, 20142014-10-21
On Monday, October 20, 2014 7:26:16 PM UTC-4, Paul Rubin wrote:> > 2b) What special considerations will you expect when creating a class? > > I guess the RAII pattern can't work the same way. Is there more?RAII works just fine; the resources are not necessarily just memory. Think about disabling interrupts, grabbing an IO device, etc. ctor/dtor RAII pattern works wonderfully for these kinds of things. Thanks! Best Regards, Dave
Reply by ●October 21, 20142014-10-21
Dave Nadler <drn@nadler.com> writes:> Often that's due to including iostreams; have you looked at > the map to see what has been dragged in and why?Interesting point about iostreams. I haven't really looked into the bloat cause. I know that everything on 64 bit systems is big. I've idly thought about compiling the program on a 32 bit system to see if it comes out smaller. The philosophy of C++ seems to be to generate fast code above everything else. When there is a trade-off between code size and speed, it will bloat the code to get more speed. For this particular program speed is what I want, since it crunches terabytes of data for weeks at a time, so I haven't worried about the bloat.
Reply by ●October 21, 20142014-10-21
On Tue, 21 Oct 2014 16:39:38 -0700, Paul Rubin wrote:> Dave Nadler <drn@nadler.com> writes: >> Often that's due to including iostreams; have you looked at >> the map to see what has been dragged in and why? > > Interesting point about iostreams. I haven't really looked into the > bloat cause. I know that everything on 64 bit systems is big. I've > idly thought about compiling the program on a 32 bit system to see if it > comes out smaller. The philosophy of C++ seems to be to generate fast > code above everything else. When there is a trade-off between code size > and speed, it will bloat the code to get more speed. For this > particular program speed is what I want, since it crunches terabytes of > data for weeks at a time, so I haven't worried about the bloat.Different compilers will make different trade-offs. If you're compiling for a 64-bit target, the compiler probably isn't going to worry about a trifling 1.2 MB when you presumably have upwards of 4 GiB of RAM (why would you be using a 64-bit OS if you have less than that?). Similarly, on a desktop/server OS where code is demand-paged, executable size doen't really matter; if large sections of code aren't used, they won't get paged in. I would expect a C++ compiler for an 8-bit or 16-bit microcontroller to make somewhat different tradeoffs. Tangentially: for iostreams, each overload of operator<< is a separate function, so you only need to link the ones which you actually use. Compare this to printf(), which may end up pulling in an entire floating point library for the sake of %f etc when you actually only need %s. Another possible source of bloat is I18N. It's possible that simply using iostreams is pulling in a chunk of locale/codecvt stuff, even if you'll only ever be using ASCII and the "C" locale. Embedded compilers typically provide options to limit supported locales or even just ignore wchar_t altogether, whereas a desktop system will probably include support for hieroglyphics, Linear-B and several dialects of Klingon for good measure.
Reply by ●October 22, 20142014-10-22
On Monday, October 20, 2014 7:26:16 PM UTC-4, Paul Rubin wrote:> Dave Nadler <drn@nadler.com> writes: > > 3) Give an example where using C++ a template can generate more > > efficient code than typical C coding. > > The C library qsort function requires you to pass a comparison method as > a function pointer, so you incur function call overhead even if you're > just comparing integers in what should be a single machine instruction. > The C++ version uses a template so the comparison can be inlined.That is at the same time a good and terrible example! Good because it illustrates the language trade-off. Bad because in a resource constrained environment, qsort can chew up more stack than is available. A few years back I encountered a stack overflow due to an ill-advised use of qsort. I replaced it with a templatized heapsort. Later I needed to sort a 2nd type. Not enough flash space for a 2nd template instantiation, so I changed to a single concrete instance that takes a pure virtual type wrapper (which provides count, comparison and swap). The wrapper hides all access from the heapsort; effectively a couple function pointers. For each type to sort, derive a trivial wrapper from the pure virtual base wrapper, and call the single instance of the sort template. All this is reflexive and easy for someone familiar with C++, and it is really powerful. Its a small amount of code to do efficient sorting without code bloat. But the point of my post was: most applicants aren't at that level, and will struggle with stuff like this... Thanks, Best Regards, Dave
Reply by ●October 22, 20142014-10-22
Dave Nadler <drn@nadler.com> writes:> Bad because in a resource constrained environment, > qsort can chew up more stack than is available.You might have been using a broken implementation of quicksort, that didn't make sure to sort the smaller partition first in its recursive step. That keeps the stack use at O(log N) instead of potentially O(N), which in some really bad implementations can happen if the vector is already sorted.> All this is reflexive and easy for someone familiar with C++ ... > But the point of my post was: most applicants aren't at that level, > and will struggle with stuff like this...It could be that embedded developers tend to be more into hardware than language geekery. You could look for programmers with a functional-programming background (ML or Haskell). C++ template generics may make more sense from that perspective.
Reply by ●October 22, 20142014-10-22
Paul Rubin wrote:> I'm hacking on a fairly small C++ program right now that compiles to a > 1.2MB binary, which seems ridiculous, like > 10x what it has any > business taking. So that's an example of object code bloat. On the > other hand, it's running on a 32GB machine so the 1.2MB is of no > consequence.File size or stripped size? C++ tends to have ridiculously long identifier names, and tons of those. 'std::cout << "foobar"' instantiates a metric ton of template classes, each of which generates just a few bytes of code, but a few hundred bytes of symbol names. A C program simply doesn't have so many symbols (main, printf, that's it). Stefan







