Embedded - 137: Pausing to Think
Episode Date: February 3, 2016Dan Saks answers many questions about C++ in embedded systems: where it works, where it doesn't, and a path to getting started. Dan Saks is the founder and president of Saks & Associates. He was a ...columnist for The C/C++ Users Journal, Embedded Systems Design and several other publications. He also served as secretary of the ANSI and ISO C++ standards committee in its early years. We touched on some of his articles: Poor reasons for rejecting C++ Preventing dynamic allocation Calling constructors with placement new Andrei suggested Sams Teach Yourself C++ in One Hour a Day, Seventh Edition by Siddhartha Rao as a good primer for experienced C programmers reluctantly learning C++. Like robots? Check out the job postings at iRobot. If you like what you see, email Chris Svec. (Yes, the guy who was on 78: Happy Cows.) Contest for Making Embedded Systems will end Feb 5, 2016.
Transcript
Discussion (0)
Welcome to Embedded FM. I'm Alicia White with Christopher White. This week, we are going to
talk to Dan Sachs about C++. I'm very excited. But before we get started, the contest to win
my book is still going on until Friday, February 5th. So that's coming up real soon. For this one, you are to
send your favorite fictional robot to me and or send your resume to Christopher Svek at iRobot,
where you can make non-fictional robots like the Roomba and the Bomb Disposal Robot.
They are looking for all sorts of help from cloud and Android developers to embedded robotics.
The jobs are in Boston and Pasadena. Check the openings in
the show notes. So send your resume to chrissvec at iRobot.com and send me your favorite fictional
robot to enter the contest. Okay, now let's get to Dan. Hi, Dan. Thanks for joining us today.
Hi. Could you tell us about yourself? Okay, I spent a number of years early in my career as a software developer,
a salaried employee, and then later as a hired gun.
However, I've spent the bulk of my career helping other programmers program better,
first as a classroom teacher at a university, then as an independent training firm.
And I also spent a fair amount of time writing columns for a variety of print and web publications,
including the C++ Users Journal and Embedded Systems Design.
And I also served as the secretary of the International C++ Standards Committee during its early years.
And for the last 20 years or so, my primary interest has been in using C++ to develop embedded systems.
Strangely enough, that's exactly what I want to talk to you about today.
Wow, that's strange. Before we get to that, we have been doing this lightning round
where we ask you questions and hope for one-word answers. So, let's try that. Chris, do you want
to go first this week? Sure. The first question is entirely appropriate to this week's discussion.
Object-oriented or procedural object-oriented favorite programming language
c++ thank you softballs it's really not a shock is it
yeah programming language you think should be taught in the first cs course in college
probably python possibly java should we bring back the dinosaurs course in college? Probably Python, possibly Java.
Should we bring back the dinosaurs?
No.
Beach or mountains?
Oh, mountains.
Mac or PC?
PC.
Would you rather use function pointers, a go--to statement or have lunch with a large spider
function pointers little or big andian little favorite c or c plus plus keyword either operator or template um okay let's go into like the actual material here
um i like c i have been using c for two decades at least um the whole thing i have to ask you is why do i need c++ why do i need to bother well um need is uh maybe that's the
operative you don't need it obviously there are people who do productive work in c and and do it
reasonably well um and when you say and why bother? Well, if you view it that way,
I'm not sure that I can make a compelling case. I find that I was naturally drawn to it. It just
made programming in my assessment more pleasant. I found it assessment, more pleasant.
I found it to be more expressive.
I found that C++ did a better job of catching my mistakes,
defending me against my own frailty.
And so I was just drawn to it.
And I think that those are the reasons.
It's not that you should feel like, oh, gosh, why should I have to do this?
It's that you should want to do it.
You should say, oh, this is a tool that's going to make my life better.
But if you see it as a burden, then don't do it.
Well, that was a shorter show.
No.
To be fair, and I should, you know, state preferences here, because you should always know the political parties are the people you're listening to.
Chris, you're very C++ pro, aren't you?
I am fairly C++ pro.
If you're going to program in a C-like language. I like C++. I've used it in many projects and many embedded projects
up until my most recent one,
which is Albin in C.
And like Dan says,
there's many things I find compelling about it
from a structural point of view
and also from,
I like the word he used,
an expressiveness point of view,
which both saves time and kind of keeps you out of trouble sometimes.
But I do work with a number of people who are colleagues who are skeptical,
especially on small embedded devices.
I find it weird that people are so skeptical.
Oh, wait a minute, I was supposed to give my political party,
but we're going to get back to that.
I was against C++ in 1999, very strongly.
The embedded compilers didn't support it.
My team didn't know it.
Everyone wanted to use only their particular favorite feature.
So trying to move over to C++ slowed us down.
But that was 15 years ago.
And now the compilers support it and most people coming out of school
know it a lot better and they are more and if they come from javascript or python they're just
it's easier for them and so you were saying the embedded small chips. Arduino, it's an 8-bit processor.
It uses C++.
You can no longer tell me that C++ can't go on embedded systems
if an 8-bit microcontroller, that's what people use for it.
So I'm not buying that excuse anymore. But so I'm more comfortable in C, but I'm interested in C++. I think
there are some things that are much easier there, but I cannot manage to convince anybody to even
try it. I feel everybody should make informed decisions about which language they're going to
use, just like you'd make an informed decision about which processor you're going to use. And so I wanted to talk to Dan about how do we become
informed? That was a handoff, Dan. Sorry, I did lecture there for a bit. It was a bit of a rant.
It was a bit of a rant, sorry. No, I was pausing. I was pausing to think. Okay. That's allowed.
Yeah. Well, I have a hypothesis about what one of the issues is with respect to the C communities embrace or failure to embrace C++. And that is that many, not all,
but a sizable portion of the people who program in C
are people who did not major in computer science in school.
They studied other disciplines like electrical engineering
or systems engineering or computer engineering,
something like that.
And programming was sort of, it wasn't
their main line of study. It was simply programming languages were tools you used to get the job done.
And in that context, and in fact, I experienced this in my own studies at school, I had instructors who, even in computer science courses, were primarily interested in
teaching concepts like algorithms and data structures or computability and things like that,
but we still did exercises using some programming language. But they would often just say,
and in this course, you're going to program in in lisp and you can buy the book in the bookstore and read it i'm not going to teach you the language
and so the actual act of programming was not something that was taught it was
people would self-teach programming languages and And so I think a large part of the
Z culture is any language worth using is a language you can teach yourself. And C++ doesn't
fit that. C++ has a lot of nuances, some features which are not self-evident, and it really helps
to learn the language,
either through formal instruction or under the guide of some mentor,
some experienced C++ programmer.
And it seems to me that a lot of C programmers,
they react adversely to that.
They don't want to have to go through that period of study
and that period of a loss of productivity
in making the transition to the new language because they don't see that it's worth it.
Now, I think the C++ community may be hurting itself in this regard as well.
I was fortunate that I learned C++ just as it was starting to become popular. And in fact, I watched the language and learned the language as it evolved.
So the C++ that I learned didn't have templates.
It didn't have exception.
It didn't have runtime type information.
It didn't have the entire STL.
And so I was able to learn those things step by step and adjust my programming style to learn those new features.
But now we have a much more mature language with a large feature set and a sizable portion of the C++ community advocates that the right way to learn the language is to learn it like it's not based in C,
that you don't use arrays, you use vectors. You don't use
pointers and structs, you use the list class or the map class. And for a large number of
applications, that is in fact the right thing to do. And if you're teaching university students programming from scratch, it's probably the right way to teach it.
But when you have industrial programmers with a very large code base of existing C and you're trying to get them to migrate that style to this more modern approach, you get a real clash of cultures you get people who are used to the c programmers used to
programming a certain way and being told by the c++ programmers well all that stuff you're doing
that's that's no good that's so passe and you should be doing it this way and that way and i
my reaction is no cut them some slack that There's nothing wrong with learning incrementally.
In fact, the reason why C++ is so popular is because it piggybacked on the popularity
of C at the beginning.
And I think there are people in the C++ community who forget, hey, you learned by spreading
it out over many years.
Why isn't that okay for other people to do it and so it's harder to find people who are still
advocating the transitional approach to learning c++ by starting with c it's in fact often very
much frowned upon by parts of the c++ community and and i think they're as i say they're right
in certain application domains you teach it like
it's a new language but i don't think that works for the embedded community no we've got a lot of
code we can't just walk away it's not just we've got a lot of code it's the resource constraints
because you mentioned stl um which is the standard template library right the standard template
library which has lots of built-in classes for things like containers and maps
and all sorts of good stuff that you...
Huge.
That everybody on C-based embedded projects,
that's kind of the first,
oh, we need a linked list.
So somebody's got to go implement a linked list
for the 4,000th time and write all the same...
I did that last week.
Same bugs all over again.
Or you need a hash table or you need a map.
And you have to do it
your particular way because you're on an embedded device and you want to save resources. I think
that's where I get a lot of pushback from colleagues also is, oh, C++ is too bloated
because they see the STL, they see things like that, and they say, we can't possibly support that
on a small chip. And for a large part of it, they're're right and that's where coming to it from a c point of view
and saying okay what can i what things can i take from c++ and use from c++ without necessarily
acquiring the whole thing uh from for this device does that make sense is that as does
does that match your experience okay yes i mean that's that is the way my training materials are structured is that i act when i
teach embedded programming in c++ we actually start in fact the way i developed my course
materials in the first place was i acquired an evaluation board and when you typically acquire
an evaluation board from some vendor they give you it used to be they'd give you a disk now you can
just download off of the web a a bundle of tools the a c and a c plus plus compiler linker etc
plus they give you lots of programming examples that show you how to blink lights and respond to
button pushes on the on the board and those examples tend to be written in C. And so I simply
took a bunch of those examples for a particular board and said, how would I rewrite them in C++
and take it through incrementally? As I go through changing structures into classes
and changing certain functions into overloaded operators, or changing hash defines into enumerated types and things like that,
I'm constantly measuring to see, have I introduced any overhead?
And what I found is there's an immense amount you can do at the low level,
modeling, for example, memory map devices as classes,
which introduces zero overhead.
I mean, really measurably zero overhead
and the key is to uh to take it slow and understand how constructs like classes
are translated into the equivalent c code and it's really not hard it's a very direct mapping
and once you get comfortable with that there's a great deal of power in that. And what you have to do is tune
out the people who are telling you, well, that's not real C++ because you're not using this feature
or that feature. And I say, what do you mean? It's better than what I was doing before.
What? Shouldn't we all just skip the polymorphic templates?
Well, I find, by the way,
templates are actually incredibly useful.
It's the polymorphous and the dynamic binding that I find to be less useful
in low-level applications,
but it still pops up once in a while
that there's a use for it.
Direct mappings seem like syntactic changes for no reason.
What sort of, you mentioned pound defs to const,
or pound defs to enumerated types.
I can sort of see that because then you,
it's like having types, and I like having types
because I like it
when the compiler tells me,
hey, you idiot, you just tried to put a UN32 in a UN8.
Maybe that wasn't what you meant to do.
At least cast it so I can figure it out.
If I wrote compilers,
the error messages would be much more amusing.
And so I understand the idea that types are a good thing.
And so going from pound defs to enumerated types, that makes sense.
It's a safety thing.
But we had enums in C.
I mean, that's a style difference.
What are the C++ things I can do and how will they make my life better other than just straight translation? Well, one of the fundamental mental shifts that takes place
when you go from C to C++ is understanding that the treatment of types is stricter,
generally stricter in C++ than it is in C.
I'll give you a couple of examples.
I was actually kind of shocked to look at the C
standard and find that, in fact, converting a pointer of one type to a pointer to another type
is actually permitted. For example, it's okay, according to the standard. It's super useful.
Converting a pointer to a float into a pointer to a long for example i've done
that now what c compilers generally do is they issue a warning for that they don't reject the
program they just say you know unless you're at the the lowest level of warnings where you say
don't bug me about anything which you should about anything. Which you should never be on.
Pardon?
You should never be on that level.
Yes, you shouldn't.
But it does come out on most compilers as a warning, not an error.
Whereas in C++, they say it's an error.
I'm not going to compile your program if you do this.
And there are other things like, for example, with enumerations, the C treatment is that an enumeration is simply an integer type.
You can treat any enumerated type like an int.
So that means that you can have an enumeration for the days of the week, Sunday, Monday, Tuesday, and another enumeration for the months January, February, March,
and you can assign a variable of type month the value Wednesday in standard C.
And in C++, you can't. They say, no, those are different types. Now,
C++ does allow conversion of an enumeration to an int, but it doesn't allow conversion of an int to an enumeration.
Whereas C will let you go back and forth.
And again, if you have a compiler which has as an enhancement warnings to catch that, then it will do that.
And of course, a lot of people say, well, I just use Lint or some other static analyzer. And I say, well, that's a good thing too.
But the C++ approach is,
hey, we just build that into the language.
And so in general,
the enforcement of types is stricter.
Yeah, I was about to say that.
In C++ than it is in C.
Go ahead.
I was about to say that, yeah,
it seems somehow backwards to expect to, a static analyzer tool to fix problems in your language.
It seems like fundamentally there's a problem with your language if you need to have tools to find errors like that.
But no, sometimes you want to be able to switch back and forth because you don't have enough.
Never mind, I'm not going to have this argument.
We have cortex processors now with plenty of memory.
We don't need to be that stingy.
There are ways to.
There are ways around it if you must.
Unions.
Oh, sorry.
Well, casts.
Yes.
Casts.
You can always force cast something if you really want.
Yeah.
Okay.
So part of the design intent of C++ is to both tighten the type checking
to make it that the compiler is more of your ally
in checking you against your own mistakes.
But then C++ turns around and gives you facilities
so that well-written C++ can actually use casting much less than C.
And an example of that is that the C way of copying blocks of memory is to use something
like memcopy. And the parameters for
both the source and the destination in memcopy are pointer to void. And pointer to void is
essentially an unchecked pointer. So you can call memcopy and you can say, I want to copy this array
of ints to an array of long doubles. And it'll copy them byte by byte and you'll get the joy of debugging that
sometime later whereas in c++ you're discouraged from using void instead what you do is you'd write
a copy template and the template you could specify it can only be used to copy something of one type
to another array of the same type you can only copy array of into array event an array of the same type. You can only copy array of int to array of int, an array of double to an
array of double. And when you do it that way, you get code which is now type safe. It's easier to
catch at compile time errors where you accidentally transform the types. And so the net effect is you don't have to use casting to um to shoehorn types
into a common function and so that makes a lot of sense what else do you have for me that's just
one thing i mean c++ is a whole big language i know because this book is huge well i mean there's
the elephant in the room which is the the the object-oriented nature of C++ versus C.
Do I have to use that?
Alternatively, my C is already object-oriented.
In the sense that, well,
when I talk about doing object-oriented programming in C,
what I'm talking about is using structs and functions
that have a parameter of type pointer
to that structure type in a
disciplined way, where essentially
the function,
the parameter pointing to that
structure we think of as the this pointer
in C++ or
the self pointer in some other object
oriented language.
The C++ way of doing it is functionally equivalent in the sense that
whenever i test this i always get almost exactly the same code in fact though i will say um
the last time that i did some real thorough tests on this, I found out that the C++ was sometimes slightly better because the,
and my inference is that the C++ compiler knew that the this pointer was special. And so it
could take certain measures in terms of parameter passing in registers to actually produce better
code. Whereas the c compiler would look at
that parameter and just say oh it's just one of many parameters what makes me think that one's
special and so on many platforms the code comes out the same but if there's a disparity my experience
has been that the object-oriented code in c in c plus plus actually comes out a tad faster. But the big notational advantage
of using object oriented programming in C++ is that it also includes access control.
You have the notion of public and private. And so you can, whereas in a C program, all you have
is that the struct, all the members are public.
And therefore, you can't put the same constraints on the casual user of your object type to say,
you can only access this part of the interface.
To the C programmer, the entire struct looks like the interface. interface and so that gives the designer of that object in C less freedom to make later changes without worrying oh I might break somebody's code because they poked around in this thing and even
though my comments said don't touch it it was only a comment in C++ it's a language tool that enforces
the rigorous nature of the interface.
What about the people who say it uses a lot more dynamic memory,
which in an embedded system, I'm still having trouble using dynamic memory.
It never quite goes the way I want it to.
Is C++ required to have dynamic memory?
No, no. A lot of people say they don't want to use C++
because it uses more dynamic memory,
and I don't quite know where that comes from.
I don't either.
I've repeated experience where I say to people,
show me the example that you're talking about,
and it's typically the response of well
i'm sure i had it somewhere or you know somebody of mine told me well that was his experience and
i took his word for it but um i keep chasing that one saying show me the example and it's a phantom because i know i i do tons of this this kind of work in terms of
crafting low-level drivers and i use classes and i use namespaces and i use operator overloading
and i am able to just avoid using dynamic memory. In fact, there are techniques that you can use to actually get compile and link time warnings to tell you that you've inadvertently used dynamic memory.
What kind of techniques?
Well, actually, I wrote this up in my column at embedded.com.
I wrote a column on exactly that.
I also had some lecture material on that from the Embedded Systems Conference.
And I can't remember exactly what the title was, but if you give me a moment, I will find it.
We can get a link for the show notes after the show.
Yeah, you can.
Yeah, we'll worry about resolving that later.
But yeah, I can provide a link to the article which showed some of those techniques.
Basically, the idea is that you, in C++, the global operator new, when you write a new expression,
you say P equals new T,
meaning P is a pointer
and I want to allocate a new object of type T
and the address of that be assigned to P equals new T.
The compiler actually translate that into a call
on a global function named operator new.
And the C++ standard allows you with certain restrictions to write your own
implementation of operator new that's specifically specified in the c++ standard that if you follow
these rules for a valid replacement function that follows certain interface conventions
certain functional
characteristics you can write your own replacement for operator new and the trick is you can write
a replacement for operator new which satisfies all of the interface constraints but is implement
implemented in a way such that if it is in uh linkedin at link time it causes a link error and so basically you don't
use the new keyword just like i don't use the malloc library call exactly if i don't want to
use dynamic memory and right but the problem is in c if you call a function that calls malloc you may not know it exactly and so i could force it if
anybody called new it would cause a problem well that leads me to another one of the things that
i've been that people have said to me which i find very odd which is well we have all these
programmers and if we switch to c++ we'd have no way to prevent them from using language features
we don't want them to use.
Yes, I like that.
Which I find strange because that's true of C as well.
There's plenty of very, very bad things you can do in C.
There may not even be language features.
It may just be because C is so powerful and low-level.
I don't really have a good response for that
because it's sort of like, well, yes, that's a problem with programming, not with language.
Have you encountered that one?
Yeah, actually, I was speaking at a conference last fall on exactly this subject.
And one person in the audience said that he's a manager of teams that develop embedded systems in C and they have
tried repeatedly to do things like hire new graduates who know C++ and have them be sort of
like the local mentors to move the team towards C++ and once again this cultural clash seemed to kick in
which is that these new hires were taught c++ in a in in the modern fashion you know they
everything was written in terms of vectors and maps and lists and so on.
And when they were confronted with this embedded software that was using arrays and unions and things like that, they couldn't connect it up. The new hires were using features that nobody else could understand.
And so they had a choice, which was, okay, we can stop all production and train all of our developers in C++, or we can try to rein in the newbies.
And ultimately, as a matter of management control,
they just told the newbies, just use C.
And that's a human problem.
It's not so much a technical problem
as it is a management problem.
And I don't have a snappy answer for that.
You have to look at your available resources.
You have to look at your tolerance for risk and your budget for training and things like that.
But there isn't a simple answer to that. And I hear, I hear, I've never actually tried C++, but I hear that it causes, that it kills baby harp seals or some sort of other outlandish.
Yes.
Yeah.
How do, so yes, you need to train your team and ideally you need to train your team together so that they know what each other knows but if i'm alone or we're we're consultants so we don't always get to control the teams or even be
part of them for very long how do we gently push people and say this is an option and it is a good one because well generally my preferred approach is to
take a lot of the risk away and so i i'm a firm advocate that the proper way to bring c++ on
board in those environments is to nibble away at it a little bit at a time and a class here
and a gnome there pardon a class here and an enum there and a const everywhere and yeah whatever that
well yeah i think the big payoff generally what i advise people to do is first thing is just take
all of your c and recompile it as c++ because it works mostly oh yeah i've never had any problem
with that the the only thing that i've ever seen uh crop up is that you might have some user
identifier which in c which happens to be a keyword in C++.
So you have to rename something.
The other issue is the way the compiler treats type checking.
Is that things that compiled without complaint in C may provoke a complaint in C++.
And the way you eliminate the complaint is by adding a cast initially.
Which you should have done anyway.
Yeah, if you were using a tool like a static analyzer,
yeah, that static analyzer would have made you do it.
Or even just looking at your warnings in your compiler.
That's right.
So then from there,
the low-hanging fruit is things like the use of reference types, which are, in my opinion, sometimes a nicer way to package function interfaces.
Other low-hanging fruit are things like function overloading.
What are reference types?
A reference is, there are different ways to explain it.
The mechanistic way to say it is, it's really a pointer in disguise. It's that when you declare a reference to an int,
you use, instead of the star operator or the asterisk, you use an ampersand. Say R is a reference to an int you use instead of the star operator the asterisk you use an ampersand
say r is a reference to an int and when you declare it you bind it to an object you say
this reference is referring to some other int n and after that you can use the reference variable
r as an alias for whatever it's referring to, N. Now, the underlying
implementation, the dirty little secret is they're implemented using pointers. They're pointers in
disguise. And I know that some C programmers look at this and say, well, pointers were bad enough
when they were out in the open. Now you want me to disguise them so I can't see the indirection.
That seems like a disaster waiting to happen.
But it actually has a lot of nice properties with respect to crafting more friendly and type-safe interfaces.
And they're easy to use and they incur no performance penalty.
And so you said the next one was function overloading.
That's when I call a function.
I have two functions
of the same name maybe with different parameters yes for example in the c library there are
functions like put char put c f put c f put char whatever uh and uh put s f put S. And the problem is that they're all variant spellings on a function named put.
Now, when programmers talk about this, I've never heard anybody say my program F put C to character.
You say it put the character to standard out or it put it to file F. You don't feel the need to say exactly which put function.
In other words, in our own minds, we overload it.
And I know, I wish I had back all the time I wasted
crafting a system of names for a bunch of related functions in C
where I want to have a half a dozen or more functions,
which all doing a similar task
but on a slightly different combination of parameter types and so you start coming up with
a name and you start using it for a while and you realize oh I didn't name that well because now I
want to add another function and it doesn't fit the naming pattern. And in C++, they're all functions named put,
all functions named get.
And as long as the parameter list
is sufficiently distinct for each one,
the compiler sorts it out.
And I think it's a real aid to usability.
Put's a really good example for that.
I don't think I've ever heard an example
that made that much sense
because yeah, you know, if I pass it a file, then I want it to be F put. And if I pass it a single
character, I want it to be put C. And yes, that makes a lot of sense. Thank you. One of, okay,
so now do you want to continue the list, recompile in C++, use reference types, function overloads, going along and continuing our path to change?
What would be next on the list? classes trying to repackage structures and related functions as a class with a public and a private
access so uh because that does a much better job of defining the interface between the components in your system i think of all the features of c++
classes with access control is gets you a lot of bang for the buck
and so if you're already familiar with doing object-oriented programming in c
that transition is actually a pretty easy step. It's actually a relief, usually.
I mean, because I've done the whole object-oriented and C
really object-oriented with strict APIs and function pointers
to mimic class methods, and wow, that gets...
Public and private headers, which never works right.
No, that works fine.
Oh, sorry.
Opaque types.
Opaque types.
Yeah.
And so then you get to C++ and real classes.
You're like, oh, that was a lot of work to implement something that's just a language feature.
Exactly.
I feel like, why are you doing all this to stay in C?
Because you're basically acting like a C++ preprocessor in your code. language feature. Exactly. I feel like, why are you doing all this to stay in C?
Because you're basically acting like a C++ pre-processor in your code.
That's what I feel like sometimes when I see this stuff. It's like, I am a pre-processor.
I am a pre-processor. Just to stay away from C++, which is strange. So, yes, I find the whole notion of object-oriented C sometimes a little baffling. But when I did my Twitter poll, people had enormous number of reasons and variety of
reasons for not switching over to C++.
And we've covered a lot of them, so I'm not going to go through too much more.
One of the ones I like, and I don't know if you agree with this or not, Dan, is I find it extremely useful for device drivers
because if you use inheritance carefully,
you can end up with device drivers
which are interchangeable for different hardware.
Yes.
And so your middle layers don't have to look any different.
You can put in simulated hardware.
I've used that in the past and found it extremely powerful.
Yep, I agree.
I often tell people to go look at the Adafruit sensor library. I don't love their interface
because it's full of floats, and I think that's really inappropriate for 8-bit processors.
But the idea of a sensor as an object and all of the things that go below it, whether it's a gyroscope or an
accelerometer or barometer, temperature, whatever.
It's just an interface makes sense like that.
But one of the reasons C programmers hate C++ on my Twitter poll involved multiple inheritance,
which I've never used.
I have.
In Qt, yeah.
You've mentioned that displays are much easier in C++.
User interfaces.
User interfaces.
They are because they're made up of objects,
so it maps to object-oriented immediately.
And inheritance makes a lot of sense
when you have something like, or subclassing makes a lot of sense when you have something like,
or subclassing makes a lot of sense when you have something that's a generic button class
that you want to style in a slightly different way but keep all the same interfaces.
So for UIs, it makes just a ton of sense.
Yes, that is almost always the example that's cited of a legitimate use for multiple inheritance.
And outside of that, I don't think I've ever used it.
What C++ features wouldn't you use in an embedded system?
What wouldn't I?
Well, I'm not sure that there's any that I'd say flat out I wouldn't use.
It very much depends on your resource requirements. And I'm talking about both space
and time. But there are certain things that I find myself using very rarely in embedded systems,
and multiple inheritance is one. And related to that is runtime type information.
Is that like an objective C where it will tell you the function name as a string?
What is runtime check?
What is runtime?
That is when you form type hierarchies.
Let's pick the well-worn example
of a hierarchy of geometric shapes where you have a base type,
which is a shape. And then you say, and the different derived types are things like circle,
square, and rectangle. And the type conversion rules in such type hierarchies is that it is safe to take a pointer or reference to any specific shape
like a circle and convert that into a pointer to a shape. And the utility of that is that suppose
you write a function that computes the area of a shape and you can pass a pointer to any shape.
So you can pass it a pointer to a circle, a pointer to a rectangle, a pointer to a triangle. And you can have one shape function that
will work for any one of those, I mean one area function, which will accept any
any shape. Now, so it's safe to convert a circle to a shape it's not safe in
general to convert a shape into a circle or a shape into a rectangle because you
might have a shape that actually is a circle and when you try to convert it
into a rectangle now you've got a a type error at runtime and so it's generally discouraged and it's generally regarded to be
a defect in your design if you find yourself having to convert in the wrong direction
but life being what it is computing problems being what they are sometimes it's a necessity
and so what runtime type information does is it allows you to do a safe runtime query to say, I've got a shape here.
Can you tell me, is it a circle?
Or can I safely convert it to a circle is actually a better way to express it.
And so it's an add-on to the capability of virtual functions.
And I have found that I can't recall when I needed that in an embedded system.
That does seem like it would make the code a little bloaty.
Well, yeah, it does have run...
That's the sort of thing that does have a runtime overhead.
And so what it does is it has the effect of making the runtime tables, the virtual tables, may increase in size.
There's more data added to the table to support the runtime type information operations.
And so that's a compiler feature? I can just turn it off on my compiler or just never make the call?
The generally advised approach is that most compilers have a compile option, a compile switch to say, disable runtime type information for this build. handling. You may find that your particular compiler handles exceptions in a way that it's overhead that you'd rather not incur. And so I can't recall the last time I saw a compiler
that didn't have a switch to say disable exception handling. I thought, I mean, when I first heard of
C++ in the 90s, exceptions were like the cool new thing.
Everybody should be using them.
Never used them.
To me, they always just seemed like go-to statements, but that's probably because I do occasionally think in go-to statements.
They do have a big benefit.
Well, let me digress for just a moment. I want to go back to something, which is one of the complaints about C++ that also surprises I don't understand why the compiler is injecting a
constructor call at this point. And it seems to me like it's overhead
that I shouldn't have to pay for. So I don't want to go there.
But the way I look at it is that constructors are functions that initialize things and destructors are functions that release
resources after you're done with something and if you don't one of the most serious problems you can
incur most subtle errors you can incur in it in a system is failure to properly initialize you know probably uh lots of hours have been lost
to people tracking down bugs and systems only to find up forgot to zero that thing out
and constructors go a long way to eliminating that error and and once you understand c++ it turns out that you can pretty well predict
when those constructors are going to be called it's very systematic and unsurprising once you
see the paradigm and so i actually think that this is one of the the biggest advantages of using
c++ for object-oriented programming is that not only do
you get classes with access control, but you get automatic compiler-generated initialization.
And it really effectively gives you guaranteed initialization. If you design a class and put
constructors in there, the users of your class have to go way out of their way to create an object
that isn't properly initialized and so a major class of errors goes away but one of the problems
with constructors is they run before main no they don't you can uh when you have objects which are local to a function the constructors
will run when that function is entered if you never enter the function you never run the
construction global objects yes they were global objects too yes don't look at me like that now
with global objects the exact timing yes that that is a pragmatic problem for embedded systems where you want to have very fine-tuned ordering of initialization.
Yeah, the GPIOs have to be initialized before the UART is initialized, before my debug log system is initialized.
That's right.
Right.
But there are techniques that you can use.
One of them is to use something called placement new or new with placement, which is a way of
manually invoking a constructor on uninitialized storage. And so for for global objects there are some useful techniques
that can give you exactly the control over the ordering that you want um but yeah it's not
quite as simple as we'd like it to be and for memory mapped objects it's a little trickier but
i've got techniques for doing that too and um and i did write some columns on that for embedded.com now what i
what i um what i wanted to bring up is that in that context you know so uh if you are using
constructors and destructors the big difference between a simple go-to um it's actually
uh the equivalent would be the c set jump and long jump functions um which
allow you to transfer control from one function to another um the problem is that if you use set
jump and long jump in a c plus plus program and the long jump transfers control from one function to another function it could bypass the invocation
of destructors you could wind up with a bunch of objects sitting on the stack whose storage
was deallocated but whose destructors never ran and therefore you could get resource corruption
and so the use of exception handling is a way to say i want the equivalent of a long jump i want
to transfer just escape from this function to some handler somewhere and i want to guarantee
though that any objects that need to be destroyed will in fact be destroyed and so i i think
exception handling it's actually a very good feature, and it's viable in many systems,
but I still caution embedded developers,
what you ought to do is write some tests.
See how your compiler deals with this.
Investigate what the overheads are,
and then decide if you can utilize that feature effectively in your environment.
If you can, it's the right way to go.
It's a more disciplined way to deal with error conditions.
One of the other things about C++ is style,
which I think is a huge can of worms.
But I wanted to read what one of the Twitter people pointed me to. And no,
I'm not using Twitter names because I'm protecting you. Trust me. C++ encourages you to write worse
code than even C does. C++ is a language that speaks to the inner intellectual. The more C++
you know, the worse you become at working with others. First,
because your particular dialects of C++ tend to isolate you. Second, because you sit in
an ivory tower that few can approach. This is a problem with all highly abstract languages.
Now, if you replace C++ in that paragraph or in that rant for Hillary Clinton, it seems to still apply.
So, that seems like it's all very much opinion and it was pointed to as fact.
What do you feel is…
Well, C is the blue-collar language.
Sorry.
Dan, what do you think about style and C++?
Is it better or worse than C or just a little different?
Well, it clearly is a richer language.
And the term I used before was it's more expressive.
I like the idea that I can think certain thoughts and then write programming language statements which i think require less
documentation to match the code up with the original thought it's more self-documenting
if done well now the flip side you know the the dark side of that um picture is that, yeah, you can make a mess of stuff. That in the hands of somebody who is
poorly trained or intent on being malicious or very asocial, yeah, you can get, it can magnify collaboration problems. And so, you know, I'm not going to say that people who have had difficulties with CPLIT, you know, there's a lot of cultural aspects to it.
How did you learn?
What is your learning style?
What is your collaborative style?
And so it's not a, there's no right or wrong here.
Well, I think it goes back, that particular... Rant? That was a mini rant. So, it's not a, I think other people may find that, yes, that
some people do have an attitude of, well, this is the theoretical better way to do things.
I can see where that attitude would develop, I guess.
Well, as Dan was saying, having fresh out of college C++ proponents to a team of industrial seed who has to get things done it's more likely
the team is going to win over the fresh-faced newbie oh i have a question i'm gonna go to
the next question unless you really want to comment on the previous well what i I think the thing that I object to most in these discussions is the blurring of the social from the technical aspects. The problems that we have with managing teams with different senses of style and taste and different learning styles, instead of saying, yes, it's a management problem, it's a people problem, they say, no, it's because C++ is a bad language.
And that is the thing that I think is wrong.
I think you can evaluate the language on its technical merits.
You can look at examples and say, is this more expressive? Is this less likely to produce subtle
bugs? How will it fare in a code review and things like that? Well, actually, that is a social
question. But the questions of efficiency, both speed and space efficiency, and portability, those are technical issues.
And when people have negative experience with C++ and blame the language, that's when I take exception to that.
Some people have mentioned debugging and name mangling as being a
reason not to use C++. I thought that was
all cleared up years ago.
Do you have any comment, Dan?
Well, I
thought it was largely cleared up as well,
but
some embedded developers are saddled
with some pretty old tools.
There's that, yes.
You know, every so often you run into a project
and you find out they're using a new tool chain
from 1998 or something like that.
Why? Because, well, it's the last one that worked
for exactly that particular configuration
that we're still supporting.
Because we're still running Windows XP.
That's right.
And that happens.
But for modern compilers, I think the name mangling is largely a non-issue.
I agree.
I haven't seen it in a number of years.
Not on any of the ARM processors I've worked on in the last three.
Oh, actually, here's more style questions for you.
Some of these are from me, because I snookered a friend into actually looking at C++ after he had a really exuberant reaction against C++. with a lot of discussion he went off and learned some my reasoning for him was that it isn't about
you as a professional long-term industrial programmer what you're doing is moving to
c++ because it's easier for the babies it's easier for the newbies and so we would like to make it easier to learn to program in our systems.
How are we going to protect our jobs if we let other people do stuff?
If we let these teeny boppers in.
Do you think that that's true?
Do you think that it's easier for new college grads to come into a C++ system versus a C system?
For an embedded system?
Yeah.
Yes.
No.
Okay.
I don't...
I would have to delve into that question a lot deeper because I'm still having trouble wrapping my head around exactly what the issue is
because the um for certain operations in a sense the map you look at your c source and you say now
what is this doing at the machine level what registers is it touching what memory locations that sort of thing and it's it's
generally a fairly direct mapping with c++ when you add things like classes and inheritance it's
still pretty direct but not quite as overt as it is in c now
the the trade-off though is that when you're programming large systems, in C, the tools you have to define the relationships between components.
As things get big, the thing that starts to burden you excessively is keeping one component separate from another how can i alter this component update it
revise it and have confidence that i'm not going to break a whole bunch of other code
because so much of a c program is is global data and public members of structures in c++
you have access control you have compiler level, hey, nobody else is touching this, and that the integrity of the interface is being preserved.
So if I go in and I make changes to the layout of some private data, I have a much higher making the program more comprehensible asrelationships of components easier is catering to babies, I don't get it.
It mostly came out of working with Arduino and Embed and how those are nominally platforms for beginners non-programmers and yet both are
generally programmed in c++ because the mappings are very hidden from the beginners
and so they don't they don't know pin maps to register blah. All they do is say pin dot on or off.
Right.
And that hides some of the complexity so that they can get moving a little faster.
Well, it's really, excuse me, I don't have a lot of experience with Arduino.
My understanding is that it's mostly a learning platform.
It's not a production platform, right?
It's an art platform more than anything else it's a it is a learning platform one-off project platform it's not a shipping platform really no but people have built it into much much larger
systems because it's a reasonable process or used for research you know robotics and things like
that where you're not building more than two or three that yeah that that was my impression okay so i'm sorry i didn't mean i just needed that
clarification before you went on so i guess i guess the question is i saw your question two
ways at least here one was you you were talking about people coming out of college with object
oriented c++ experience is it easier for them to come into an embedded environment
that uses C++?
I didn't realize you were talking about coming from Arduino and embed,
which I'd have to take issue with that because while they are C++,
you know, effectively, that's not really part of,
it's not a big deal as part of the language.
It's C++, but it's mostly procedural?
No.
No, in Arduino, if you get a shield, you usually end up with a class.
You include the header file, and then you treat it like an object.
So if you have the Wi-Fi class, you're using it like an object.
Yeah, but are you making your own objects?
Not often.
That's what I'm saying.
No, because then you have to go out of sketch land
and into C++ land and suddenly you actually know what's behind the curtain. So yeah, so me
personally, I don't find that there's, I mean, I guess there's a familiarity that would be nice,
but there's still a big gap. Fair enough. In embed, you're encouraged more to write things.
Embed is just C++ as far as I remember.
It is, and people use it with C, and yet if you search for blah, BLE module, you end up with a class because that just tends to be...
Well, if you're extending Arduino, you write classes, I suppose. I was just surprised that the people I knew
who were getting into embedded systems
were all, came
from C++, not because
of academics, but because
that's where the
quote, easy platforms were.
But
Andre from the Great White North, who was
the person that we convinced to read a C++ book in the last couple months, said regarding style,
I'm finding that C++ has a style, whereas C is a cylinder of pureed worms, where consensus must be imputed by decree rather than by best practice.
Pureed worms. Yeah, I had to quote that.
Thank you, Andre.
I'd like to bring up another point, which I didn't want to let it fall through the cracks.
One of the attitudes, I think, that C programmers in embedded systems tend to acquire
is this feeling that no matter how hard you try to write carefully written,
even statically analyzed code,
you're still going to get bugs, nasty bugs you have to debug at runtime.
But in fact, I think the culture is more dominated by people who say,
oh, what the heck, let's just throw together the code, get it to compile,
so we can get to the real work, which is debugging,
which I think is an unfortunate mindset.
Now, what happens is if that's your mindset towards c
when you get to c plus plus all those nice features which introduce layers of abstraction
get in your way actually get in the way of debugging that i hear that complaint a lot
is that it's just so much harder to debug this stuff and there's a cultural shift that has to take place you have to you have to stop
thinking that the real work is debugging and start thinking that the real work is the coding
that you have to take advantage of the type system and the access control
to try as best you can to reduce the incident, to take things that would have been runtime errors
and turn them into compile time or link time errors.
Now, that doesn't mean you're going to get to the point
where there will be no bugs.
But then the other way to defend against that stuff
is through the careful use of assertion checks
that you build into your interfaces,
pre and post condition checks,
so that these things are automated and
you know if you have an expectation about the range of values for a particular input to a function
you can now easily spot the places where that value can arrive inside the class interface
and just put assertion checks to catch that stuff.
And so you want to take a more rigorous approach so that you essentially try as hard as you can
to wean yourself away from debugging. Now, I live in the real world. This is aspirational.
It's not something that you're necessarily going to achieve because sometimes those assertion checks come at a runtime penalty that you can't afford.
But by the careful use of things like replacing parameters of an integer type
with parameters of an enumeration type,
you can actually turn what would have been a runtime error, a range error,
into a compile time typing error.
And then you don't need the runtime check at all.
And you keep pushing in this direction,
and you find that,
hey, I'm spending less and less time in my debugger.
And the fact that C++ has these layers of abstraction
that make debugging harder
becomes less and less of an issue.
But if you don't make that mental shift right you always
say hey this c++ is a debugging nightmare that that is exactly what i wanted from you dan really
was that about debugging that it is using c++ is different nobody is saying it isn't different but you know debugging can be really fun
keep smashing bugs is great until you realize you can't figure this one out and then it's all gone
bad and if it turns out it's from an initialization error it could be weeks if you just don't
or because your code isn't properly modular or or somebody's stepping on toes they shouldn't
because they're violating a private-public access...
This makes so much more sense to me.
My idea that it's for newbies is not as good as it's easier
not to debug.
It's harder to debug, but it's easier not to debug and not,
it's harder to debug,
but it's easier not to spend all of your time debugging is just,
yes.
Okay.
I'm on board.
Now that's my experience.
I mean, that's,
it's,
it's not everybody's experience,
but that's been my experience.
I think that it's a hard experience to get around because a lot of us did have bad experiences
with C++ the first time we tried it after years of C, either because it wasn't portable
yet or the compilers weren't that good yet.
But it's been 15 years since I had that argument and was right.
Now I'm afraid if I had that argument, it would not.
Yeah, I would be on the side of C++ this time.
Chris, do you have any more questions?
I have one final question, more of a request for a blessing.
I often like to use the singleton design pattern for device drivers and things,
and C++ makes that quite easy.
I have heard that's a terrible thing to do.
I would just like Dan to tell me
either that I should go repent
or that I should be allowed
to use it in certain cases.
But what's your motivation
for using the singleton?
To avoid global objects i can't remember you only
have one spy driver you i only have one yes i only have one device of a certain type and i want to
make it available throughout the code without doing a lot of standing on my head passing it to objects and such. Yeah. I think that's the real reason for doing it
is to get an assurance,
an automated assurance
that you're only going to try to instantiate the object once
because clearly if you have only one instance
of that particular hardware device,
you don't want somebody creating, declaring more objects of that particular hardware device you don't want somebody you know creating
declaring more objects of that type and say hey i know i just added another port to my board by
constructing another it's magic that's right um and you know the alternative is you wind up with
two separate threads of execution thinking they both own the same resource or something like yes so i i think
that using techniques like that are generally good approaches i mean there might be alternatives
that might satisfy you for example uh sometimes a mono state pattern might be a good alternative
you know but but i tend to prefer, I think, the singleton.
I'm furiously Googling that.
The monostate?
Yes.
Yeah, the monostate actually allows for the appearance of multiple objects,
but they're all mapped onto the same construct,
and it only gets initialized once.
Oh, interesting. Okay.
Maybe we should have spent time talking about design patterns, but...
Well...
Maybe next time.
Oh, one of the other comments before I let you go,
because I know I'm almost out of time here.
One of the things people pointed out about C
is that it has really stopped changing since, well, 1999, C99.
Or even before that, if you're Microsoft Visual Studio.
Really?
Yes.
No, that was my problem.
Visual Studio 13 has C99. but people don't know that much about c99 because the books seem to stop getting updated after c85
and they don't seem to know about the new stuff with c++ you mentioned classes being the way to go do you have any books that you'd recommend books on on learning c++
not necessarily for embedded systems but maybe without all of the fluffy stuff
without all of the you shall use stl in all cases because i can't i can't afford that lambdas actually i think yeah
this is a deficiency see a lot of us learned to program in c by reading kern hannah ritchie yeah
yeah and it is nice and concise it's very well suited for professional programmers if you have some understanding of programming picking this up as
a good quick introduction to programming in c is it's pretty hard to beat and um unfortunately the
corresponding book by bjarnes strostrup the c++ programming language is about four or five times yeah and and fairly daunting and um and now and
the books that are more the size of kernahan and ritchie is there's a book called accelerated c++
by uh koenig and mu and but that book takes the approach of teaching the standard library components,
vectors and maps and sets and things like that, in preference to using the more primitive data
structures like arrays and pointers and structures, which is considered to be the modern C++ learning style and is very appropriate,
except in certain embedded cultures, the ones we've been talking about.
And so there seems to be a gap.
I'm not familiar with a book that is a KNR-level treatment of learning C++ in an incremental style,
which I think is appropriate for a lot of embedded developers with existing code bases.
I think it's just a, it's a whole.
Now, that doesn't mean such a book doesn't exist, but I'm not familiar with one.
That's fair um i will give a
shout out to siddhartha rose sam's teach yourself c++ in one hour a day um which andre said went
through a nice logical method of here's a chunk here's a chunk without a lot of here's the whole style you must use at all.
But if anybody else out there has a good C++ book,
one that reminds you of K&R or Harbison and Steele for C,
let us know.
Maybe there is something out there we just don't know.
Okay. Okay. It's been a long one, hasn't it? We needed something meatier after last week's
giggle fest. Dan, do you have any last thoughts you'd like to leave us with?
Only that I urge people to, in discussions of this sort, try very hard to separate out the technical issues of
language from the people, the management, the social issues of collaborative software development.
And that I think that we can have a much more productive and informed discussion if people would be aware of how they keep blurring these lines and try to make every effort to separate this out and say, you know, here's what my concern really is, rather than attribute a people problem to a tool.
Good advice. Really good advice. My guest has been Dan Sachs,
the founder and president of Sachs and Associates.
He was the columnist for the C C plus plus users journal,
embedded systems design,
and several other publications.
He also served as secretary of the ANSI and ISO C plus plus standards
committee in his early years.
We're honored to have him on.
We're also honored that you gave us
some more iTunes reviews and good stars.
We appreciate it when you take the time to do that
and to share our show with others.
I'd like to send a special thanks out
to Christopher Svek and Andre from the Great White North
as they helped me prep for this show.
Thank you also to Christopher
for producing and co-hosting.
And thank you, of course, for listening.
Hit the contact link on Embedded FM
if you'd like to say hello
or email us show at Embedded FM.
You can use that address
to enter the favorite fictional robot contest
where you can win a copy of my book
or join iRobot.
They're both good options.
We'll be here next week. In the meantime, I have a couple of final thoughts to leave you with,
because I did send out that Twitter message where I said, if you are an embedded programmer who
primarily uses C, why don't you use C++? And I got so many good reasons and good tweets back. Even if I
didn't agree with all of them, they were very helpful. My favorite of them all, though, came
from James Wack. Because of ignorance, I suppose, my knowledge of C is much more comprehensive,
and I feel that I have more control over it. I thought that was the most honest, best reason.
And now a quote from somebody a little more famous, Mahatma Gandhi.
Live as though you were to die tomorrow.
Learn as if you were to live forever.
Embedded FM is an independently produced radio show
that focuses on the many aspects of engineering.
It is a production of Logical Elegance, an embedded software consulting company in California.
If there are advertisements in the show, we did not put them there and do not receive any revenue from them.
At this time, our sole sponsor remains Logical Elegance.