Embedded - 247: He’s Not Going to Cut That, Is He?

Episode Date: June 1, 2018

Jason Turner (@lefticus) of the CPPCast (@cppcast) spoke with us about modern C++ in embedded systems. Jason’s articles can be found on EmptyCrate.com. You can also contact him there and find out mo...re about his training sessions. Jason’s video channel is on C++ Weekly and includes an ARM emulator written in C++, running on Compiler Explorer. Jason often uses Compiler Explorerby Matt Godbolt (Embedded #190: Trust Me, I’m Right). Jason’s C++ Best Practices Guide on Github. Listen to CPPCast at cppcast.comor on your favorite podcast app. CPPCon 2016 keynote Rich Code for Tiny Computers, where Jason writes a Commodore 64 game in C++. Jason recommended looking at Odin Holmes’ twitter (@odinthenerd) as well as Odin’s talks from CPPCon (such as his 2017 talk about agent based class design). Odin runs an embedded C++ conference in Germany called Embo++. Also look into Jens Weller’s Meeting C++conference. During the show, Elecia was looking at cppreference.com. She would also like to apologize to Bjarne Stroustrup. Embedded Patreon

Transcript
Discussion (0)
Starting point is 00:00:00 Hello, and welcome to Embedded. I'm Eliseo White, alongside Christopher White. We're going to be talking about C++ with Jason Turner of the CPP podcast. Hi, Jason. Welcome to the show. Hi, thank you for having me on. Could you tell us a bit about yourself? I am a C++ developer. I've been working with C++ since 1997 or something was the first time that I used it as a hobby language professionally for over 16 years now. And I am a trainer. And as
Starting point is 00:00:42 you mentioned, host of CBP cast, and host of C++ Weekly, which is my YouTube channel. Okay. Now, I have a lot of questions about C++ because it's a language I've heard about for a long time. Just a few decades. I don't really use as much as I feel like I should. On the other hand, before we do that, I want to do lightning round where we ask you short questions and we want short answers. And if we're behaving ourselves, we won't ask why and how and all of the follow-up questions. Okay. Favorite C++ keyword?
Starting point is 00:01:21 Oh, constexpr. Yeah, I knew that one. A tip you think everyone should know about life or about C++? Whichever. Whichever. Both. Hmm.
Starting point is 00:01:35 Oh, uh, well, wait, this is supposed to be lightning round. It's supposed to be answering these quickly, huh? Bam,
Starting point is 00:01:40 bam, bam. Um, I'll edit it. So it seems quick in the end. And he'll take that out too. Okay. Maybe. too. Okay. Maybe.
Starting point is 00:01:47 Maybe. Maybe, yes, exactly. Oh. I'm sorry, I just have no idea. Okay. Would you rather give a talk at a trade show style conference or an academic style conference? I guess I've only ever done academic style conferences, so I have to answer that. Or maybe I could say trade show because I've never done it before.
Starting point is 00:02:16 Which is better, constructors or destructors? Destructors. Would you rather spend your next work day programming or giving class? At the moment, programming, because I've been giving a lot of classes lately. Which would you prefer to learn things with great breadth or depth? Depth. Okay. Okay. Now on to to the meteor questions um c++ why use it wow why let's start
Starting point is 00:02:55 with the big question yeah so you know it's an easy one um you know i can answer this in like five seconds maybe um uh i would say main reason why is because c++ has been designed from originally with the principle of zero zero overhead abstractions so anything that c++ has in the core language would not the the principle basically says it is not possible to implement it by hand any better than the thing that's built into the language. And that's something we can pretty much rely on. I've been trying to make a point of demonstrating that for a while now, the past few years since I've been speaking at conferences and such. So if we know what the zero overhead abstractions are,
Starting point is 00:03:40 we use them appropriately, we can get really high level code that compiles to nearly nothing. You use Matt Godbolt's Compiler Explorer quite a bit in your talks to show how you go from what looks like a completely foreign templated constexpr sort of line to four or five assembly lines. How did you find that? And how do you figure out how to make your C++ do that? Well, Matt's website, which is Compiler Explorer, godbolt.org, it was, I'm not sure when I first became aware of it, but I do remember the first time that I showed an example of the output in a conference talk, and everyone was basically like, whoa, how'd you get the assembly language output of what you just did there? I can't even guess how many tens of thousands of lines of code I've written into a compiler explorer window just to explore what it's possible for the compiler to optimize and what the resulting code is. And it does take a little bit of practice to be aware of what things the compiler
Starting point is 00:04:58 can optimize and what things it can't. And it definitely takes discipline to know when to use the right techniques and not just throw everything at the compiler all the time simply because you can. Because C++ is a multi-paradigm language with an awful lot that you can throw at the compiler for sure. There really is an awful lot. I mean, I thought I spoke C++ and then I watched one of your presentations and realized that I spoke C with classes. Maybe C++ from the 90s. Yeah, C++98. Well, you know, even though I've been doing a lot of thinking about this lately,
Starting point is 00:05:39 and C++11, 14, 17, they all enable higher level abstractions. One of the main things that we got in C++ 11 is lambdas. And variadic templates are cool, but let's just go past that for the moment. And lambda is just a user-defined anonymous function. And the compiler treats it truly as that. It's just a function, but it's easy to declare it. And then in C++ 14, we got generic lambdas. So we can just say that the parameter types are auto,
Starting point is 00:06:11 and that's a shortcut for making a template function. So it looks really clean and easy from the user's perspective, from the programmer's perspective, but it's something that the compiler can just do the optimal thing with as much as it wants to. And we can see, generally speaking, that lambdas are also something that's a zero cost abstraction. I think of lambdas as sort of inline functions that are passed by pointer sort of into another function. And in Python, I think of them as more generators, although I know Python does have more proper lambdas,
Starting point is 00:06:48 but the generators are kind of what I understand. How far off am I? So if you have a lambda that does not have any captures, so it knows nothing about the surrounding scope that it was created in, it is a function pointer. It's totally fair to think of it as a function pointer. It's totally fair to think of it as a function pointer. If the lambda has a capture, so you're saying there's some variable in the local scope that I would like to either take a copy of or a reference to this local
Starting point is 00:07:14 variable, then it has to become an object, something that can own that variable. And at that point, it's still something that is very efficiently managed because, well, C++ compilers have been very good at optimizing objects for at least the past 35 years or so. So it's just an object that you pass around that happens to have a couple of variables in it and the ability to call it like it's a function. Okay. What is constexpr? I mean, I have more questions on that, but really constexpr, Chris explained it to me and what I heard was wah, wah, wah, wah. You know, if you don't mind, I would like to take a quick step back just on the topic of C++ being a large language. Yes.
Starting point is 00:08:02 I've done this comparison recently, and if you look at the actual C++ core language spec, if you compare it to C, it's big. It's like 400 pages, something like that. If you compare it to Java's core language spec and C Sharp's core language spec, it's actually quite small. Like hundreds of pages smaller. I just thought I'd throw that out there.
Starting point is 00:08:24 Now, it has nothing on Python, like hundreds of pages smaller. I just thought I'd throw that out there. Now, it has nothing on Python, because Python's language spec is like 100 pages or something, and Ruby's language spec, one of the two of them, I forget which one now, doesn't even seem to have an official language spec. They just kind of do whatever they want to in the language. So I'm not sure about that.
Starting point is 00:08:43 But anyhow, I just wanted to make that aside. Well, I think you were diving into some specific things, but I think from the point that we don't, both of us, haven't used C++. I've used it more. I used it using with Qt maybe eight years ago or so, or maybe five, six years ago, but not in recent memory. I guess from our perspective as embedded developers, we have the subset of C++ that we kind of understand, classes, private, public inheritance,
Starting point is 00:09:15 maybe not using multiple inheritance. Templates are a scary thing that we don't want to touch. Exceptions are a scary thing we don't want to touch. And that's pretty much the ballgame. We don't use STL, or I guess that's been subsumed by something else. So I guess what's changed beyond kind of that core of the object-oriented structure? And what might be of use to people who are kind of wary of C++ as being bloated. Or confusing.
Starting point is 00:09:47 Or confusing. See, I was just going to ask about each individual thing. Well, I at least want to have the header there before we do that. It is better because it's broader. Okay, so in the broad scope, it's fair to say very little realistically has changed. We've just been given cleaner abstractions for how to talk about these things. I mean, you could implement your own class that had the call operator, the operator paren overloaded in C++ 98. And that is effectively
Starting point is 00:10:18 exactly what a lambda is doing for you. But the lambda gives you like a one line way of doing this instead of like a 10line way of doing it. And it's in the same scope. It's something that's highly optimizable by the compiler, and it knows exactly how to deal with these things. And we've gotten ranged for loops, which are a convenient way of looping over anything that's iteratable, and that includes C-style arrays and standard library containers, like you mentioned the STL, but if you're not using those, that's fine. And all that does is compile directly into something that calls, basically, the begin and the end over the range of the for loop,
Starting point is 00:11:02 or excuse me, over the elements in the container for you. And for a C-style array, that's the same thing. It gets a pointer to the beginning of the C style array and a pointer to one past the end of it and loops in between that range and operates on it. So it's like, you know, one line version of something that would have been three lines with the potential for bugs of accidentally having the wrong size of the array or iterating off the end of it if we were using some sort of a magic number marker or looking for a null terminator or something like that but if we know the size of it at compile time we can pass it to the array to excuse me to the ranged for loop and the compiler can do something very good with it in fact ranged for loops in a
Starting point is 00:11:41 way become something that we some of us like to call a negative cost abstraction, because now the compiler knows the exact range of the loop at compile time, and it says, well, I know exactly three items are in this or whatever, and it can unroll those and do constant folding and make the whole loop just go away. Or if it's values that it knows at compile time, then the entire calculation or whatever you're doing goes away at compile time. So lambda is ranged for loops. We'll get to constexpr in a moment. I think we do need to talk about that.
Starting point is 00:12:14 Templates have stayed the same for the most part. They've gotten a little bit more features to them. I wouldn't say they've necessarily gotten easier to use, but we do have variadic lambdas now, which is basically a way of saying I want, excuse me, variadic templates. I got off track there somehow. It's basically saying we've got a function that can take any number of parameters. And now in C, you have variadic functions, but in C, you don't know at compile time really what the types of those arguments are. They're basically void pointers, and you have to do something with them correctly. So that's like printf.
Starting point is 00:12:52 Sorry, go ahead. That's like printf. Printf. I just want to make sure we have concrete examples for some of these things. Yes, sorry, like printf. And now in C++11, we have a variadic template way of doing that, and we know at compile time exactly what types of parameters have been passed to our function. And the compiler can do all the compile time checks to know exactly that this thing is doing that it's supposed to be able to match up types that are in the constant character string with the things that were passed into it. And that's like compiler magic. That's not anything that's built into either the C or the C++ language spec.
Starting point is 00:13:37 That's been one of the interesting things about C++ is learning that you should trust the compiler even more. I mean, in C, we've been saying, yeah, okay, at one time you could optimize your C, you could optimize your assembly to be better than your C, but now you should just be looking at your assembly, optimizing your C if you have to. You should definitely be writing in C because your compilers have gotten a lot better.
Starting point is 00:14:02 And it sounds like in C++, they've gotten even better because so many people are working on it. Oh, yeah. I mean, what optimizing compilers can do today, and to be totally fair, our C++ optimizing compilers are C optimizing compilers, right?
Starting point is 00:14:18 It's the same back end for Clang, GCC, and Visual Studio. And we can pretty much rely on the optimizer to do the right thing. It's just in C++, because we have more type information knowable at compile time, the compiler has that much more to work with to make it possible to optimize it.
Starting point is 00:14:39 Okay. So we're giving it more information and it's doing stuff with it. Exactly. We're giving it more information and it's doing stuff with it. So. We're giving it more information and it's doing stuff with it. So one example that I've been showing a lot to my students lately is you take a C-style array. Now, it's effectively impossible to pass a C-style array around, right?
Starting point is 00:14:58 If you pass it to a function, it's a pointer. That's correct, right? Yeah, yeah. Okay. And so C++ has this thing uh that was added in c++ 11 called standard array and it's it's i mean it's really really really simple template class all it is is a class that contains a c style array but the type and size of this array is baked into the type information for standard array. Now, if I pass a standard array to a function, I'm not just passing a pointer, I'm passing a pointer or
Starting point is 00:15:34 a reference to an object that knows how big it is. So every calling function knows I'm working on an array that is however many elements wide, and that gives the compiler that much more information to work with. So any for loop or anything, again, coming back to like arranged for loop or something, anything that's going to iterate over that data knows the full size and type information at compile time and is able to, again, do more with it, more constant folding, loop unrolling, whatever it needs to do.
Starting point is 00:16:12 But does the memory get... Is the memory static? Is it at compile time? Is it at runtime? Am I worried about... I mean, in embedded systems, it's like no dynamic memory. You have to have all static memory. It's just one of those rules that eventually we'll grow out of,
Starting point is 00:16:28 but we haven't yet. Be for yourself. No, sure. Some of us have heaps. We're talking about stuff that, like if I'm talking about a C++ standard array, the new container type add-in, C++11, it is something that lives on the stack.
Starting point is 00:16:46 You know exactly where it is. And you can pass a pointer to it if you want to, or I mean a reference, but when we're talking about the disassembly, a pointer and a reference are the same thing, to another function, and the function can operate on it. Or you can return them from functions, which returning a C-style array is effectively impossible as well, right? You can return it from a function, and with guaranteed return value optimization in C++17, you know for a fact that there will be no copy or movement of that data at all. So you don't have to do a heap allocation to create an array and return it like you might have to in C. You can create a C++11 standard array, return it from a function, and ultimately what the
Starting point is 00:17:31 compiler does is construct that in place at the call site. So anything that would cost something goes away, guaranteed by the standard. So if I had done an array, it would come off the stack as soon as I came back from the function, it would just be destroyed. And the only way that I could pass it back if I wasn't using a heap is if I made it a global variable or static. But you're saying I can pass it back and it's on the stack and it doesn't go away. That seems magic. Well, no, it's not. I mean, because if you returned a structure from a C style array, excuse me, a structure from a function in C, then you would get data returned back, right?
Starting point is 00:18:21 It's not going to automatically become a pointer. It's just this ugliness that exists in the old array. And well, I say as C++ developer, the old array style and C style arrays, that they just decay to pointers. There's like no way around it. But in C++ or in C even, if you return a structure from a function, that's a thing, right? It's an object, it's not a pointer. I guess I don't know what the correct term is to use in C for what a structure returned from a function is actually doing. A copy. A block of memory.
Starting point is 00:18:54 A copy. It's a block of memory, it's copied, yeah. And in C++17, it's guaranteed to not be a copy. It's like the compiler, so if I call a function that is returning a data structure in C++, specifically in C++ 17, although compilers really have been doing this as far as I can trace back since 1996, I have not found a compiler that would not do this for C++. If you say, I have a structure, so like my struct, whatever it is, equals some function call.
Starting point is 00:19:27 And that function returns that structure back to you. The compiler allocates on the stack where the memory needs to be in the resulting place for the caller. And then it passes forward to the call, to the function that it's calling, a pointer to that memory location and says, when you fill in that data structure, fill it in back here where the calling actually took place. So returning, for example, a data structure from a function in C++ is effectively, and I'm exaggerating a slight bit where I'm, you know, simplifying a slight bit, has basically been free for at least the past 33 years. Never been a copy. Okay. There are caveats. Yeah. Of course. But, uh, yeah, I mean, so that, that's just one thing that I like to point out to
Starting point is 00:20:19 my students when I'm, when I'm showing them, uh, just, you know, where C++ can be efficient. Yeah, I think those are the main things really that we've gotten in the last, say, seven years from the language, though I'm sure I'm missing something. Well, constexpr, we still haven't talked about that. We'll get back to it. Okay. we'll get back to it okay uh how do i learn c++ and what do i learn if i say i want to learn c++ do i go for 11 do i go for 17 do i just try to refresh for 98 what what do i do and how well okay there's so from the perspective of your listeners, I believe, since we're talking about an embedded world here, one of the problems that we have is embedded processor manufacturers
Starting point is 00:21:14 not supporting C++ very well. So, I mean, the compilers are there, right? 90% of the chips out there, at least, I'm sure, have official support from Clang or GCC, right? I assume are the main compilers you all are using, except for the rare, the ones that were vendor-specific. Is that correct? Mostly, yeah. I mean, I think the vast majority of the common chips are GCC-able. Yeah, a lot of people are using other compilers,
Starting point is 00:21:50 IAR and Kyle, to name two. But all of the ARM chips now can be supported with GCC and free versus pay-for. A lot of people are going for free, even though the pay for sometimes is a better format although often isn't so uh yeah arm i i've played a tiny bit with avr and msp430 chips which both have support from clang and gcc as well and we're talking those are teeny teeny tiny chips right um well i don't know how how
Starting point is 00:22:26 how much capability you can get in an rv an r avr these days but it's an 8-bit processor right yeah let's just go with 8-bit processor and laugh and walk away 8-bit processor yeah so uh so avr has full complete c++ support from GCC and Clang. But if you're using an ARM chip or something that's a little bit more complex, that maybe has multiple cores or multiple CPUs in it or something, getting a good support from your CPU vendor is going to be a little bit harder. Apparently, like I just saw a talk from Michael Case on this at C++ Now, which was a conference a couple weeks ago,
Starting point is 00:23:09 where he was pointing out that basically it comes down to the linker script not being complete. Like that was the main thing that he found. Otherwise, the tooling is there. And the linker script becomes a bit of a problem for C++ if you want to support things like exceptions because the compiler needs to know where to put these things in memory. But if you're not worrying about exceptions and you're just using the regular language features
Starting point is 00:23:35 and you have a compiler that can support it, then I would say just learn C++17. I would not go before C++14. I personally consider C++14 to kind of be a bug fix to C++11. It has just a few minor tweaks that are really important for really being able to make the most out of the newer abstractions. But otherwise, I would say try to forget what you think you know from C++ and try really, really hard to not think of C++ as C with extras. Think of C++ as learning a different language, then you will hopefully have a little bit more success with not trying to apply what you know from C and think, oh, this is the efficient way to do it, because that's not true in C++.
Starting point is 00:24:35 And I've had this experience with teaching students. I've had to be like, you know, they'd be like, well, but it's more efficient to call malloc and return a pointer to the thing. And I'm like, no, it really, really isn't, I promise you. And I'll bring it up in the compiler explorer, and I'll show them the differences and be like, look, you had to do a heap allocation here, and in C++, all the code that we just wrote completely went away.
Starting point is 00:25:00 So just trying to break that mindset, it's not C with extras extras it is a different programming language is i think good that's one of the things that an embedded developer might take issue with some of the hidden nature of what what's happening with memory because a lot of the time we're doing things as explicitly as possible because we have very limited memory available. Right. And it's in various segments that might be well-defined in various sizes. So if we know we're, you know, basically getting things statically 90% of the time, maybe we have a small heap, but we're very careful about using that.
Starting point is 00:25:41 Is there, the worry that comes up in my mind is, okay, well C++ is doing these things very efficiently, but I don't know where it's, where it's doing these things. And I don't know. I don't know at any given moment, necessarily how much is taken for certain operations. Does that make sense as a worry?
Starting point is 00:26:01 I know it may not be valid, but I know it makes sense. And so a talk I gave it may not be valid, but... No, it makes sense. So a talk I gave a couple of years ago, which was writing a simple Pong game for the Commodore 64 in C++17. Okay. The talk had a few hundred lines of code to it, and I walked the audience through,
Starting point is 00:26:22 like, okay, I'm going to do this thing, I'm going to do this thing, and I'm going to add some lambdas here and whatever. And with each step, I had the compiler explorer up, and I was showing what it compiled to. And one of the comments I got from this was, I never knew it was possible to make assembly language so interesting. But I did this for 90 minutes on, well, 70 minutes on stage. And the kind of behind-the-scenes bit of this story is, it did take, it was very carefully crafted code to know exactly what the compiler was going to generate.
Starting point is 00:27:00 And part of that was because I was writing code for the 6502, MOS 6502 CPU, ultimately, which is very old now. And I was, there's no compiler for the 6502. So I was actually having to transcode it how much memory was used or where things lived on the stack or whatever. I also had to be specifically concerned about each type of x86 instruction that was even being generated to make sure it was doing that, preparing for that talk, is I did the entire thing in the Compiler Explorer. And I got to become comfortable with what the compiler was able to optimize. And now, today, two years later, if I'm unsure about what something's going to do, I throw it in the Compiler Explorer. I run through it, and I go, oh, okay, right, right. I can trust the compiler's able to optimize this, And now I'm going to move on with my life. And, you know, with a little bit of experience now, I know what's going to happen. But for the most part, like the compiler is never going to dynamically allocate memory for you. That's just simply not going to happen. So if you learn where it is always going to optimize things, like return values from functions, return value optimization,
Starting point is 00:28:28 then you learn to trust those. And if you learn what kind of algorithmic things it can do, like, for example, templates. A template in C++ is never less efficient than writing the same code by hand. It's impossible for it to be less efficient. Because all the compiler did was swap out the types that you passed into it with the types that should have been there. So you put in type name placeholders, it swaps them out with the actual types that were used to compile time.
Starting point is 00:29:00 So you can call the same function four different ways with four different types, and it will always generate the most efficient version of that function possible. And then it would likely, not always, but it has the ability to then inline those functions, which will make the code that much more efficient if it can. But it will make the code larger no no larger than if you had written like if i make a template that takes one type you know it says a simple template to type in it and i call it with four different types it will be no larger than if i had written four different versions of that same function and oftentimes smaller than if i had written four different versions of the same function right because so i i have a code in that i work on and I had written four different versions of the same function. Right, so I have a code that I work on and I have several different versions of, say, a matrix mult. And one's fixed point, one's floating point,
Starting point is 00:29:55 or, you know, things like that. And that's not a great example because we have to do different things in there. But yeah, there's two different copies. And even if you have the same exact operation, you're going to end up with two different copies in C, just because you're multiplying ints or floats, right? Right. Yeah.
Starting point is 00:30:14 And you're saying that won't happen with templates, if done correctly. Well, I'm saying if I write a template function, one time I call it with ints, and one time I call it with floats, the compiler will generate for me two different versions. And it's sometimes possible that it will actually result in a smaller binary than two different versions, but assume it just made those two different versions for you. Exactly.
Starting point is 00:30:41 So the only time template bloat comes in is if you are reckless with that, and you create templates and call them with 10,000 different types, because you can, because in C++, generating many of the features are scrutinized because everybody says bloat or slower or bigger or something. And so just about every feature I can ask you about, you will be able to tell me is just as good as if you did it in C. Because that has been the drive for 35 years. Right. And I'm coming from an unfair standpoint because I teach people all the time that it's that. Yeah. But how do I, how do... Let me ask a question while you're thinking about this. I think one angle that people might challenge some of this is saying, well, in C, most things are kind of explicit, right?
Starting point is 00:31:48 You do something and you kind of know what's happening. That's not really true because there's all sorts of examples where operator precedence and type promotion are all screwy. And then by the time the optimizer gets its hand on it and then the CPU executes the instructions out of order and everything else, you have no idea what happened, really. Right, right. But you feel like you did.
Starting point is 00:32:09 But with C++, now we have all these features, and some of them do very implicit things. Like you mentioned, if you have a template and then you kind of carelessly call it with a bunch of different types, that's going to explode your code. But you might not make that connection if you're not a very sophisticated developer or have sort of knowledge of how templates work
Starting point is 00:32:33 under the hood. Right. Now, I accept that argument, but I would say this. I think the likelihood of accidentally calling a templated function with a bunch of different types is low. Just like the likelihood of accidentally calling, well, I don't know. I mean, if you had a function in C, you have one version that takes an int, one version that takes a float. Now you call it with a double, you call it with a short, you call it with a long. The compiler is going to do implicit. Well, yeah. You name them all differently. You don't do anything implicit there. If you call it with a double, you're calling matrix multiply underscore float.
Starting point is 00:33:15 Yes. That's my point though. You're calling matrix underscore multiply, sorry, float, but you're calling it with a double. That's what I'm trying to get at. And now you've just done a truncation, right? And that's allowed in C, right? Yes. And now is the compiler warning you? Well, usually it'll warn double to float. Okay, it would warn double to float.
Starting point is 00:33:37 Truncations are usually warned. But Christopher's question went back to my hesitation, and that is you can do things in C very explicitly. And the way I do them, and the way Christopher does them, and the way other people do them, they may be stylistically different, but on the whole, they're not that different. But when I look at C++ code, it feels almost artisanal. It is an expression of whoever wrote it and how they feel about templates and STL and classes. And it's about them as much as the problem they're trying to solve. Is that just because I'm on the outside or is there some truth to that?
Starting point is 00:34:27 There's probably some truth to that. Yeah. That doesn't seem good. I want science. I want one way to do it. I don't want... Wait, wait, wait, wait, wait. You're telling me that doesn't happen with C code?
Starting point is 00:34:39 It totally does. There's very readable C code and very not readable C code and very... And we can have a war about where the curly braces go and how many spaces are in a tab and whether you should have Hungarian notation or if every variable should be named I. Or if there's one term for each function. I'm pretty sure we've all agreed that Hung... I'm sorry, go ahead.
Starting point is 00:34:59 Yeah, there's just tons of stylistic things that happen. But in C++, I mean, in C, once you get rid of all of the top surface level, then you're left with five different algorithmic ways to do it. And I feel like in C++, you're left with 500 algorithmic ways to do it. And because of that, I feel like I'm not learning it right. I feel like I can't win. I can't learn it well enough to be confident. So you feel like you can be a it right i feel like i can't i can't win i can't learn it well enough to be confident so you feel like you can be a doctrinaire c person easily but you have to be
Starting point is 00:35:30 a cafeteria catholic with c++ uh terrible analogy i have no idea what that meant but you can there's more to pick and choose from and leave leave aside So you can go whole hog into C++ if you want, and that's a different style than, say, using three-quarters of it. And maybe it's not great to use three-quarters of it. So I personally, like, this comes up all the time. You know, people say C++ is bloated, they should break compatibility with the past, basically. As a teacher and as a programmer, there is very few things I would remove from the language.
Starting point is 00:36:12 Because they all have real legitimate, well, most of them have real legitimate uses. And it does take discipline to know when to use them. But it's no different than any other language. I don't think i mean and see if you see code that is calling melloc everywhere and never uses the stack you're gonna think this is bad code right i hope yeah yeah if if you see code that is um uh constantly like i don't know i can't think of anything else that's great right now without repeating myself. But just like, consider if you had, I mean, most of us these days are polyglots, we know something about other languages. If you could have getting the efficiency of C,
Starting point is 00:37:08 or better in some cases, then does that seem worth learning the extra features? Yeah, definitely. As long as I could find a way to learn those extra features in a way that I could use them. And in C++, I can learn about lambda functions, and I can learn about templates, and even STL, which I do want to get to, and the standard
Starting point is 00:37:36 library stuff. But when I read other people's code, I look at one person's code, and it's this way. And I look at another person's code and it's this way. And I look at another person's code that's doing essentially the same thing and it's that way. And I don't know what I want my code to look like because I'm too much of a newbie. There's no classical C++ that I am aware of. Although as I was preparing for this, I realized you have a GitHub that's about this, don't you? I have a, well, I have a GitHub. Let's see. I have the CPP Starter Project. The Best Practices Manual. Oh, I have that as well.
Starting point is 00:38:20 The Best Practices Manual is not everything that I teach for sure, but it's cppbestpractices.com. And it's mostly about, you know, basically keeping things clean and simple. It did have some nice references to other tools and looking at how you put things together. I guess if I'd had that earlier, maybe I wouldn't feel so leery about some of the new features. I really have gone through this process where I read a book and then I'm totally daunted by all the things I'm learning and then I go read some stuff and it's all different. And it's true. And we have a problem. mean we but is that is that
Starting point is 00:39:07 specific to c++ i mean i don't think it is it goes back to the artisanal code i've seen python that's confusing it's confusingly different like oh like 2.6 i've seen i've seen pearl that is i mean i've seen people have arguments and code reviews on python where it's like oh you're not using this language feature why are you doing it this way like oh because it's much easier for people who come from from c and don't know python well and it's like what uh-huh it's not the pythonic way to do it exactly yeah um i totally i totally agree with you and it is a problem that we have like if you look at Stack Overflow, for example, and it's probably true of any language, but I know it's really true in C++ land, that the early answers that get upvoted and get the most links from Google are the things that come up in a search.
Starting point is 00:39:59 And they're not always the right thing or the good thing to do. And there is difference between C++98 and C++17. And the difference is daunting enough that if I know one better than the other, and a teammate is the other way, our code is not going to look similar. It's going to be confusing for the third person who comes in and knows C++14. That's when you hire a competent trainer to come in and get you all on the same page. What is it you do during your day job, Jason? I occasionally teach people at companies how to write good, clean, modern C++. Let's see. I have some listener questions i want to go through if that's okay with you sure uh can you elaborate on the usage of pass by reference versus pass by value some people say
Starting point is 00:40:55 pass by value is always faster but uh the listener has read that in certain cases pass by value a copy can be faster depending on the type we've covered this a little bit but maybe the direct question is cool sir so um it depends an awful lot on the cpu architecture that you're programming for if you're talking amd 64 64-bit intel compatible stuff these days and the 64-bit C++ ABI. If the things that you're passing can fit in 64 bits or less, then passing by value is almost always more efficient, because the compiler will simply shove that into a register. And if you're passing by reference, then it's going to have to do a memory and direction to
Starting point is 00:41:45 actually access the data of the thing that you passed in and note that you said 64 bits but if you're on a 32-bit processor then it's 32 bits if you're on an 8-bit processor it's 8 bits on a 32 bit intel architecture it's going on the stack regardless it's not going to go into that highly efficient register parameter that's we don't care about intel it's all about arm go into that highly efficient register parameter. That's the difference. Oh, we don't care about Intel. It's all about ARM. I don't. Let's see. I'm not sure the answer there either, honestly. I've just looked at it.
Starting point is 00:42:11 I'm pretty sure. I mean, we can go to godbolt.org and try it out. But your answer, I agree with the caveat that it depends on how big your processor is. Yeah. And I actually, if i might plug my c++ youtube channel i have an episode coming up i haven't actually even edited it yet so you have to subscribe now um and like two months probably that is comparing these different things and what the compiler can do with packing data into registers and passing to function parameters
Starting point is 00:42:42 and this is c++ weekly where where you look at a screen and you talk and you look at the assembly and it's all pretty self-contained. Pretty much. Each episode is pretty much self-contained. I have a few multi-parters, but there's somewhere between five and ten minutes each and it's just a thing that I want to talk about. Sometimes people will like comment like, oh, you're teaching bad practice here or whatever. And I'm like, I'm not necessarily teaching anything. I'm just talking about the thing that I felt like talking about that week. So, you know, don't take everything that's on that channel is like Jason taught this is the best practice thing to do here.
Starting point is 00:43:20 No, it's just an interesting thing to talk about. Okay, next listener question. From a listener who's a fan of C++ for embedded, but mostly in the C with glasses camp. And he avoids templates because they generate lots of code, which we kind of talked about. That's your fault. And it's sometimes painful to debug. Which means that he's closest to C++98. He admits to improvements with the null pointer and shared pointer types and better initialization. But what new features in C++11 or 17 or 14
Starting point is 00:43:55 do you think most apply to the constrained environment of embedded development? And I want to add a caveat to that. What features do you think we should be avoiding as well as applying? Well, in a constrained environment, I avoid all dynamic allocations, personally. Exceptions,
Starting point is 00:44:16 totally agree. Some CPUs, it's impossible to support exceptions. Exceptions, but that's not new, right? We've been avoiding exceptions for a long time right i've avoided them on processors that could support them so yeah and the community as a whole is is largely avoiding exceptions altogether at this point because there are better ways in many in many cases for how to handle errors. But yeah, we touched on the bloat or not from templates, null pointer.
Starting point is 00:44:50 So I would say most of what's been added is things that have made it better, even from an embedded standpoint. And I would say definitely you should be looking at the algorithms because all but three of the algorithms can be implemented in a zero cost way. And those are stable sort, stable partition. And no, I always forget the third one. Well, anyhow, a third. And what's that?
Starting point is 00:45:20 A third one. A third one. Yes. And and lamb, basically. So if you're doing any kind of data processing at all, you should be looking at algorithms and lambdas and using them in your C++11 forward code. And I can just about guarantee we'll make your code both your actual code
Starting point is 00:45:40 that you programmed shorter and more efficient. Well, this goes to one of the things that we commonly complain about as a bed of developers is oh well i'm starting a new project i'd better rewrite linked list and and a circular buffer and q and things and you know those are all container classes that exist and and yeah it kills me that we aren't doing that. And there are, I mean, there are search and sort algorithms. You don't have to look up a bubble sort on Stack Overflow and copy it into your code anymore. I don't get enough Wikipedia. If you use, I mean, standard vector can actually be super efficient as well. I mean, if you're using it, you know, in a constrained context,
Starting point is 00:46:26 it will do exactly one allocation and exactly one deallocation, exactly like you would expect a hand-rolled thing to do in C, but you didn't have to write it yourself. In the strings library, I am not the only person who has had bugs in their string handling system. I'm just not. But, I mean, but these are things that take size. These are libraries that, you know, I don't know how you'd say, I don't want that, right, if it's part of the language. Well, you just link time optimization.
Starting point is 00:47:01 Sure. Well, and basically all of the standard library things are templates. They don't do anything to your compiled code unless you use them. Because a template effectively doesn't exist. Right, okay. An instantiation of a template exists. So, I mean, I can include the vector header and I can link against the C++ runtime and not see vector anywhere in the resulting binary. Now, if I actually create a vector of integers,
Starting point is 00:47:31 then I'll see the code that was around it get inlined into my code, basically. Okay, well, that's one of those implicit things then that you might get excited and say, well, I'm going to grab this string. I'm going to do all the string manipulation using the standard stuff, but it's too big to fit on my 8-bit AVR with 32K
Starting point is 00:47:49 and fit my program. I mean, those are real concerns. Yeah, kind of. I mean, I can show you examples where I create strings and run algorithms on them, and depending on what's known at compile time, the resulting binary is just like return five. Right.
Starting point is 00:48:08 Like, you know, because they are all templates, the compiler has complete visibility into what those things are doing. And it can do very efficient things with them at compile time if it has enough information to. And I mean, we think about algorithms and some of these are big and interesting. I mean, I've written I to A too many times,
Starting point is 00:48:31 and to find it in the algorithm is just really nice, even though it's going to be a little bigger because I don't need everything, but I don't care. That's worth a few extra bytes. But max, I mean, usually we pound to find max, and then you have to have the right number of parens, and you have to think about what if there's a plus plus when it gets passed in. It's almost impossible to get right as a macro, yeah.
Starting point is 00:48:53 But here, I mean, there's a function that's part of the language. It's compiler developers have thought about all these things you're going to write bugs about, or I'm going to write bugs about. And I guess as a rejoinder to my own complaint is, if you're working on a tiny system, you're always aware of, you have to always be aware of the implications of what you're using. And that doesn't change whether you're doing C or C++.
Starting point is 00:49:21 You used AVR, but this is, I mean, AVR is Arduino, and Arduino is C++. I mean, it's not, and Arduino is C++. I mean, it's not the best of C++, but they do templates and classes and multiple inheritance. I don't think it's... But they're not necessarily trying to fit that alongside a Bluetooth stack. I mean, from a product development standpoint. Well, yes, and now we can't talk about Arduino. I mean, yeah, great development standpoint. Well, yes. And now we can't talk about Arduino.
Starting point is 00:49:46 That's why, I mean, yeah, great. You can do whatever you want when you've got Arduino and you throw your hands up and cry when it doesn't fit. But, you know, somebody hands you a processor and says, okay, this is what it has to do. And we have these libraries we're bringing in. You have 5K. Now you have to make some choices
Starting point is 00:50:02 and be aware of the implications of the things that you pull in that. I mean, that's, but Jason is saying you don't pull in anything you don't need. Right. And that would be, I'm saying that would be true of anything you're doing. I would like to say that before you get too excited about a to I or I to
Starting point is 00:50:17 a, or, um, those functions, but those actually come from the C standard library, don't they? I think so. No, I think I was out of there at that point. Let me see.
Starting point is 00:50:33 Oh, maybe they do. A lot of those functions that are around that area rely on the currently set locale, which is its own can of worms. Yeah, let's not go there. Yeah. Okay, so there are things. So I'm looking at this C++ reference page, and there's algorithms library and iterators library,
Starting point is 00:50:54 numerics library, and then down here with the line separating it, there's standard library extensions. Okay. Where is STL? I remember STL. STL was okay. it was a little complicated
Starting point is 00:51:06 is it is it in the iterators and algorithms part or is it in the standard library extensions part okay uh which page are you looking at i'm sorry cpp reference.com um okay just making sure okay so um the stl the standard template library has kind of always been a colloquial thing like as far as i know the standard never actually called it that no it's it is the thing that is the containers and the algorithms basically with the concept of you have a container that's got begin and end iterators and you can pass these iterators into your algorithms basically that's what we think of as the standard template library there were a bunch of functions too aren't there i don't know if we would have ever called them
Starting point is 00:51:59 the standard that is part of the stl or not i I don't know. In any way, STL doesn't really exist anymore. It's part of the language. Oh, yeah, yeah. It's been part of the language since C++98. Wow. I am so old. But I'm pretty sure I used the STL namespace like 10 years ago. Well, there was Boost.
Starting point is 00:52:23 I used Boost, which was sort of STL I've never seen the STL namespace I've seen STD maybe that's what I'm thinking of well it's been a while I would like to comment on the topic of templates and before we run out of time
Starting point is 00:52:39 there's a developer who's been doing a lot of conference speaking lately his name is Odin Holmes and he is Odin Holmes. And he is Odin the Nerd, if you want to look him up on Twitter or anything like that. He is big in the embedded space, and he is a C++ developer. And one of the things that his library does, using templates, is he can say, like, I've got my embedded device, and I need to set
Starting point is 00:53:06 these seven bits on an eight-bit register. And, you know, he just, like, writes very clean-looking code that says, I'm setting bit two, I'm setting bit five, I'm setting bit one, I'm setting bit four, whatever. And his library is able to take that, say, well, you set seven out of eight bits, so I have to read that register, update those seven bits, and write it back. Or, if he wrote all eight of the bits, it can, at compile time, say, I know that you wrote all eight of the bits, there's no reason for me to execute the read, I'll do a single eight-bit write right and he has shown in his own code like considerable like 30 compile time compile size savings and some of his embedded work if i'm getting that number right he could correct me i think it's it's on the order of i mean it's like considerable by taking
Starting point is 00:54:01 advantage of techniques like that taking advantage of templates to calculate at compile time the things that they needed to know. Okay, let's go back to listener questions. This is a bit tough. One listener in the avionics community mentions the need for certification. And FAA, FDA for medical, highly critical applications like space, what parts of C++ have been okayed for that use?
Starting point is 00:54:35 Much of the standard library, as far as I know, and as far as this listener knew, hasn't passed any certification for the highly critical applications. Yeah, and I have, honestly, it's not something I can speak to. I know I've heard that exceptions aren't allowed to be used, for example, but outside of that, I don't really know. Oh, and I mean, there are small pieces of guidance. FAA has guidance on object-oriented practices and multiple inheritance, basically. They say no unless it's for the interface.
Starting point is 00:55:11 Yeah, that doesn't make any sense to me because... The rules for that are you don't want code you're not using. Every line of code, every function needs to be traceable to requirement. So if you have a multiple inheritance case where you have some code off that isn't currently being called or that may not be called, you don't want it in your code because you can't trace the requirement to anything. Multiple inheritance adds a layer of indirection that makes it difficult to do the direct trace. It doesn't have to, though. I mean, you can do multiple inheritance without using virtual functions
Starting point is 00:55:50 and just inherit multiple behaviors, and then you know exactly what's happening. Yes. Yes. And I'm sure that somebody could make that argument. I do know that the development for the F-35 fighter jet, a great deal of it was C++. So I think they even have a published best practices thing. So people are using it. I don't know what you have to do to get it certified, but it's not impossible.
Starting point is 00:56:23 Okay. Constexpr. Constexpr. Constexpr. Should we talk about Constexpr? We have more questions. I would love to talk about Constexpr. Let's go with Constexpr. I have one more listener question I want to get to, but let's go with Constexpr.
Starting point is 00:56:36 What is Constexpr other than something really fun to say? Constexpr, Constexpr, Constexpr. Constexpr is Portmondeux. Can I portmonde can i get that can i say that right it's a it's a um it is a constant expression okay and what you are telling the compiler is it is possible to do this thing at compile time that's all you're saying. Now, if you have enough things that can be done at compile time, and you want to call some of them in a compile time context, I could say, you know, constexpr int i equals call some function. And some function has to be constexpr, that function itself has to be marked constexpr. Unfortunately, we can't define that.
Starting point is 00:57:26 But we're telling the compiler, I want to do this thing at compile time, and I'm calling a function that I already told you ahead of time can be done at compile time. Then the compiler does it at compile time. Are these macros? No. This is like, say you want a table of values.
Starting point is 00:57:42 And usually we go to Excel excel and we generate the table or we write a separate c program that generates a header file and that runs a function and generates your table this is saying just put that in your code and the compiler will do that for you and then turn it into a constant so your constexpr would be like for all of the values for zero to 360 and one degree things do sine x and put that in this array i think so is that do i have that right that is 100 correct except for the fact that we don't have a sine function that is constexpr well fine but we're getting there that should that should be in C++20, I think. Or you could write your own sign function.
Starting point is 00:58:27 Let's just say you wrote your own. And that's not hard. I mean, writing... Wait a minute. You might have tables of tables. It's constexpr all the way down. It's constexpr all the way down. So for the example of a table,
Starting point is 00:58:42 a project that I was just recently working on was I was writing my own ARM emulator because I thought this would be something interesting to do. And I started realizing as I'm typing this, like, part of my goal is to apply as many of the best practices that I teach to a brand new project. And I'm like, well, this could be constexpr, and this could be constexpr, and this could be constexpr. And then I realized that the whole thing could be constexpr, and this could be constexpr, and this could be constexpr. And then I realized that the whole thing could be constexpr. But a part of it was the opcode decoding. I needed a table to say, well, what kind of opcode is this? And I needed that table to be sorted because I needed the most specific version to be checked first. And I realized, well, there's no reason why I can't just write this table sorting in a constexpr context as well. So I have all generated at for me at compile time the opcode decoding logic that's stored in a table that's generated at compile time
Starting point is 00:59:36 in the sorted order at compile time that I need to decode the opcodes for my instructions in my ARM emulator. And the end result is that I have an ARM emulator that I can, if I really want to, pass it a string of bytes at compile time, and have it tell me what the resulting registers and memory layout would be at compile time. Which I couldn't do in my Excel version, which I could do up to that point. Right. I mean, there is some temptation. I ended up making a fair number of tables fonts command table command tables and state machines yeah um and doing them in excel or
Starting point is 01:00:17 handwriting them in code it's not that big a deal um but then you have a synchronization issue, right? And a maintenance issue. Yeah. Yeah. I used to use awk for synchronization. Awk. I've never done that before. Let's not talk about that. Awk 2020 is going to have a lot of cool features.
Starting point is 01:00:43 That's awesome. So, yeah, that's basically what constexpr is. You can just say, I want to do this in compile time. Which I guess has a lot of advantages, although they're not apparent. I mean, you have to think about what you're doing. Well, to me, it's like there's a bunch of times when I've tried to do things like that and see
Starting point is 01:01:06 to have it say what are you doing this is you can't evaluate this so I can think of a lot of places where you know just it seems like something you can do you find out you can't and you learn where you can't use it and now now you can yeah I mean there's definitely still limitations you can't throw exceptions, which is fine, because you didn't want to be throwing exceptions anyhow, right? And you can't do dynamic allocation, but you didn't want to be doing dynamic allocation anyhow. I would say the main actual downside to it is that
Starting point is 01:01:39 because the compiler has to know the definition at compile time, the definition effectively has to live in your header file. Otherwise, there's no way for the compiler to see the definition of it. Yeah, yeah, yeah. Okay, before we close the show, tell me about CppCast. It's interviews, and you talk to interesting people, but I've always thought embeddededded was pretty niche. Both.
Starting point is 01:02:08 But a C++ podcast, that seems even more so. How do you keep it going? What's it like? Why do you do it? How much new is happening in C++? All the questions. Tell me about it. Oh, goodness.
Starting point is 01:02:22 Okay. So we've been doing it for about three years now. We have over 120 episodes. No, it's more than that. Sorry. Whatever it is, we've been doing it for over three years now. We have a guest virtually every week. Sometimes it doesn't work out and we end up just doing a news-based episode.
Starting point is 01:02:39 But there is constant news to talk about. The numbers that I'm aware of say that there's about 4.5 million C++ developers around the world right now. We've got something like six active conferences and new ones being formed regularly. So there's always something to talk about from the latest standards meeting or the last conference that happened, people that are speaking at the conferences, or what people are discussing as the latest best practices, that kind of thing. And occasionally we get the controversial thing on or get someone from a different programming language or talk about embedded or, you know, whatever. But yeah, it's not terribly hard finding guests, really. There's a lot of people that want to talk about
Starting point is 01:03:21 their personal projects or their talks or their research or whatever. Cool. Did I answer all those questions? I think so, yes. I try to. I'm still going back to there are multiple C++ academic conferences. Are there multiple are there any embedded academic conferences? I don't think there's any academic embedded. Yeah, maybe that or or robotics or it would be a sub application field now i feel like i feel bad like i should revisit this and make sure i understood what you meant by academic conference i mean it's it's people just talking about ideas and it's not sponsored by any particular company
Starting point is 01:04:03 um is that an academic conference are they presenting papers and stuff yeah not not in the same way no it's it's not like uh yeah i don't know i guess it's called with it's we say that we're submitting papers to the conference but it really doesn't. It's not like a published paper kind of thing. It's pretty academic-ish. This is the thing that I'm talking about. It's more academic than the embedded ones are.
Starting point is 01:04:32 I mean, lately our better conferences have been through Hackaday and places that are less sponsored. We'll see. Maybe it'll get better. Yeah, I could say it's definitely not a trade show, I don't think. But it seems like it's somewhere between those two worlds, maybe a little bit. Well, I'm currently trying
Starting point is 01:04:53 to figure out if I can really convince people who are having a conference about jellyfish to let me go. Which is an academic conference about jellyfish. Wow. So that will be, you know, completely pointless. Let you go and speak or just let you go? Oh, just let me go.
Starting point is 01:05:11 Okay. Maybe I could just wear a jellyfish hat. Okay. For people who are inspired to learn more about C++ and how to use it in embedded systems, what would you recommend? I know you teach classes, but do you have books you recommend or sites that people can learn more about the latest in C++ and how it doesn't suck for embedded?
Starting point is 01:05:36 Okay, so specifically about embedded, I guess I would... Or about new C++. I mean, at this point, there's thousands of hours of conference talks online. Yeah. Like literally thousands of hours. Yes. But you go and like look at the top rated talks
Starting point is 01:05:54 from CppCon and you will find a lot of good talks. And there's, yeah. I mean, so I mentioned Odin Holmes. He's doing a lot of talking about embedded. Michael Case is also an embedded developer. Um, uh, yeah, I mean, uh, so I mentioned Odin Holmes. He's doing a lot of talking about embedded. Michael Case is also an embedded developer. I mentioned him earlier. Um, you could look up talks from either of those people and see what they are talking about.
Starting point is 01:06:16 Uh, Odin's, uh, tweets, um, a lot. Uh, and then there's, uh, let's see, a new Twitter and conference that are starting to, oh, yeah, so there's two conferences around in the C++ embedded space. One is called Embo++, and it is held in Germany every year. That's Odin's conference. And then there's one called Meeting Embedded that will be getting started for the first time this year in Berlin. And that is Jens Weller. And you can follow Meeting C++, which opened my eyes to a lot of things. And I know you use Matt Godbolt's Compiler Explorer because it really does show you what's happening. And that is weirdly persuasive. It is, yes.
Starting point is 01:07:22 Sorry, go ahead. Well, I was going to take the bold stance of recommending my own CppCon talk from two years ago. And Rich Code for Tiny Machines was the name of it, the one that I mentioned already that I demonstrate writing a Commodore 64 game. And it's an exercise in what's possible and just how much optimization the compiler is capable of doing. And how helpless you become when you lose your keyboard keys. It was a fun talk. I do recommend it. My laptop had crashed right at the beginning of that one, too. So it was exciting.
Starting point is 01:08:02 You handled it with aplomb. Thank you. Jason, do you have any thoughts you'd like to leave us with? Oh, I don't know. Never stop learning, I guess. That sounds like a good one. I can make up some random something. I think it must be time for Jason to go eat.
Starting point is 01:08:23 I've already had dinner, actually, but thank you for the concern. Our guest has been Jason Turner, host of the CPPcast and independent developer and trainer. You can reach him at EmptyCrate or find him on Twitter. Of course, we'll have links in the show notes. Thank you for being with us, Jason. Thank you for having me on. Thank you also to Christopher for producing and co-hosting. Thank you for being with us, Jason. Thank you for having me on. Thank you also to Christopher for producing and co-hosting. Thank you for listening. Thank you to Matt Godbolt for the introduction.
Starting point is 01:08:52 Thank you to Joel Sherrill and other listeners who contributed questions. If you'd like to know who the next guest is and get your question in, well, you have to join the Embedded FM Slack channel. And to join the Embedded FM Slack channel, you have to join the embedded fm slack channel and to join the embedded fm slack channel you have to kick in a buck a month on patreon for at least one month it doesn't come out too much does it it comes out to a dollar we don't have ads and we do greatly appreciate your support on the other hand if you just want to say hello you can contact us at show at embedded.fm hit the contacts link on embedded.fm.
Starting point is 01:09:25 So now I have a question. I have a quote, a quote to leave you with this one from Bjorn Strussup. Nope. Bjorn Strussup. Nope. Jarn Strussup. Bjorn Strustrup. Bjorn Strustrup. This one from Bjorn Strustrup. He's not going to cut those, is he? Embedded 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 money from them. At this time, our sponsors are Logical Elegance and listeners like you.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.