15 ms·
Modern C++ for C Programmers (2018)
- ipnon 5y agoIs Rust preferable for the embedded systems engineer who is primarily concerned with being modern?
- maxk42 5y agoBeing modern for its own sake? I suppose it would be preferable, since Rust is newer and evolving rapidly. But if you're concerned with being employed and a wide variety of powerful tooling at your fingertips then C++ is probably a better bet. (Note: I am neither a C++ nor Rust developer, so I don't have a dog in this fight.)
- adamnemecek 5y agoRust is always preferable.
- netr0ute 5y agoOn what merits?
- Inityx 5y agoMemory safety, build system, dependency management, the usual
- adamnemecek 5y agoIt's just overall productivity.
- netr0ute 5y agoCan you define productivity?
- smoldesu 5y agoI can't speak for everyone, but I spent an unconscionable amount of time managing dependencies and libraries in C++. In Rust, it's the easiest part of my workflow.
- adamnemecek 5y agoYou can speak for everyone. C++ dependency management is just...I don't even know where to begin.
- dkersten 5y ago> You can speak for everyone. Not really. I only use header-only libraries and dependency management is a breeze for me. I check each library out as a git submodule into a third-party subdirectory in my project directory, point the includes path at it and off I go. When I want to upgrade, I pull the git tag/branch/commit I want and recompile. Its pretty simple.
- adamnemecek 5y agoI mean that's cool but you are definitely working against the language as opposed to having the language support you. Also this works nicely for self contained dependencies, and much less nicely for not self contained dependencies.
- dkersten 5y ago> you are definitely working against the language How so? > Also this works nicely for self contained dependencies, and much less nicely for not self contained dependencies. Doesn't matter. You said: "You can speak for everyone." which is simply not true, as I have outlined. You didn't say anything about not self contained dependencies or whatnot. The person you replied to said "I spent an unconscionable amount of time managing dependencies and libraries in C++" and I... well, don't. So clearly not everybody does.
- jimbob45 5y agoIs there anything C++ does better at this point? Outside of compatibility, that is.
- rvz 5y agoToo bad there is no first-class production ready GUI library for Rust that I can use for embedded systems. Qt and C++ it is then.
- pjmlp 5y agoAnd on the context of Windows IoT, UWP is all about .NET and C++, with the Rust bindings pretty much still doing baby steps.
- dmitrygr 5y agoWhy is "being modern" a concern? Luckily, embedded is not the web, where 5000 frameworks sprout over lunch. I've never heard of anyone in embedded caring about being modern. Only about solving the problems efficiently. So i am curious: why do you ask?
- ipnon 5y agoEmbedded engineering seems to be a lost art in the America. The typical American programmer is certainly not an embedded engineer, and our industry and American universities focus mainly on the application layer of both practice and theory. My university's[a] computer architecture and operating systems courses are both taught entirely using simulation, either simulated hardware or virtual machines, and we would certainly never write our own bootloaders or really ever put code to the metal. It all seems more Shenzhen than Silicon Valley, like part of the stack is simply a bygone thing of the past for American software engineers. Neither C nor C++ could be considered new languages, and this seems to contribute to this estimation of embedded engineering as a "lost art." C and C++ give a "here be dragons feeling," that only the best engineers can hope to avoid pointer pitfalls and memory leaks. I wonder if Rust's advances in programming language theory could alleviate this problem. The new generation of programmers I feel I belong to are comfortable with functional programming, advanced types, and facile tooling like NPM. I have personally found embedded engineering underrated in American industry, both for fun and profit. If adopting modern practices leads to further embedded engineering adoption, that would be a worthwhile pursuit for individuals and our community. Perhaps this takes the form of Rust. [a] Top 300 in global ranking, with a standard but not cutting edge computer science program unlike Stanford or CMU. Having gone to only one university I admit this confusion could simply be a failing of my own education.
- dmitrygr 5y agoEmbedded has always been a "I learned this myself, while tinkering, then expanded my knowledge by tinkering more, and then by having a job doing something similar" kind of field. So that is not new.
- 5y ago
- CraigJPerry 5y agoFor embedded, i would have said C not C++. C is more prevalent still. For some industries where security or correctness guarantees are necessary, you see things like MISRA C used rather than Rust (or cpp).
- michaelsbradley 5y agoThere's also the Ravenscar profile[1] for Ada and the SPARK language[2]. How those compare in marketshare to MIRSA C, I'm not sure, I'm not in that field, though I've enjoyed reading about them at a conceptual level. [1] https://en.wikipedia.org/wiki/Ravenscar_profile https://en.wikipedia.org/wiki/Ravenscar_profile [2] https://en.wikipedia.org/wiki/SPARK_(programming_language) https://en.wikipedia.org/wiki/SPARK_(programming_language) [&] https://docs.adacore.com/sparkdocs-docs/Examiner_Ravenscar.htm https://docs.adacore.com/sparkdocs-docs/Examiner_Ravenscar.h...
- oddity 5y agoAnecdotally, everything I've seen (hardware drivers) has been in (MISRA) C or a subset of C++. Ironically, many of the alternatives require too much discipline to keep devs happy. MISRA C at least lets them pretend they're in their happy place.
- dexterhaslem 5y agoive been in the misra c realm a while and romanticized ada, spark, ravenscar profile etc. i think if you have a team and problem that can go 100% in on it, its unmatched (and some industries certainly do, aviation, autopilots, internal fuze controls etc..)
- oddity 5y ago(I'm assuming you're coming from C and don't already know C++ because of the linked article) If the ecosystem that's available is sufficient for your needs on the platforms you care about and you're not interested in easy compatibility with a C/C++ codebase or your existing C knowledge, I would recommend Rust over C++ whenever possible (C is a different question since it fills a slightly different niche and doesn't really have a solid alternative yet imo). Rust has a much simpler and well-chosen set and interaction of features than C++, but it does that by dropping many of the compatibility constraints of C and C++ (and making assumptions that are easier to make in 2021 than 30+ years ago). Compiler errors also more honestly reflect the learning curve, so it can feel more punishing at the start, but has a shorter learning curve to reach functionally correct code, where with C++ you might easily have been using it for 10+ years and still learn you've been doing something wrong the whole time. That's a big set of ifs, though. It's possible that the compiler errors are discouraging enough that C++ might feel like a more comfortable choice (I would encourage you to not let this be your reason unless you're just interested in solving a one-time problem). I keep checking in on Rust to see how small and dependency free I can get the compiled binary, and I usually need a mess of nightly features. The ecosystem is also still a mess. There are a few great libraries, but otherwise it's a minefield of 0.x releases for most dependencies (admittedly, some of the most important ones are autogenerated bindings where the version number is meaningless). Bindings are really easy to write with Rust, however, and it's one of the few languages that really gets that right, but it's nowhere near as convenient as calling/using C or C++ from C++. Most of these issues are consequences of C and C++ having the existing inertia, but it is what it is. Some people want to ship things and not join a community. If you're trying to get a job or just learn: learn both. C++ isn't going to go away completely any time soon, but, with every month that passes, there are fewer and fewer technical reasons to justify starting a new project in it vs Rust. Choosing an inferior tool because it's the only one you understand might often be the correct choice, but it's not a choice you want to have to make.
- ipnon 5y agoThank you for this thoughtful comment. It seems the present moment is a flux for embedded programming languages, there is still a choice to make. Maybe we will be discussing "Modern Rust for C++ Programmers" in a few decades on HN!
- Bayart 5y agoI don't know that « being modern » should ever be a primary concern. Especially when it comes to embedded where stable features and APIs are important. It's largely the realm of C, with some industries working in Ada/SPARK. In terms of its profile, Rust fits the bill for being a good system/embedded programming language some day, but I don't know if it's mature and stable enough yet to be what you'd pick for a really serious job. As for C++, I don't really see the point if you don't have technical debt.
- pjmlp 5y agoSome embedded standards like AUTOSAR, require C++ not C.
- epistasis 5y agoI'm not a systems engineer, I just do data analysis and algorithms that sometimes need to go really fast. I only recently investigated rust, and was hugely impressed with it. I regret not investigating it earlier. Language support for ownership and lifetime of variables is such a huge step up for writing code. Trying to do this through as hoc conventions in C, or through RAII in C++, is a lot harder. I haven't yet had a chance to write anything significant in rust beyond a few small test projects, but next time I want to beat Python performance on something I'll be using Rust instead of Cython or C or C++.
- brooksbp 5y agoIt gets real fun when "going fast" is less about the software and more about what's happening inside the chip!
- sharikone 5y agoI guess so. Some newer libraries, especially if they target "modern backend" stuff like webassembly, websockets, ... are written in Rust. When safety is a concern it could be really preferable. But, say, if you don't have a good support for your platform Rust is not useful. Ditto for most existing codebases. And in any case I don't see why your primary concern should be being modern vs getting things to work well
- osivertsson 5y agoMost places I’ve done embedded dev at have been C or C++. Actually all, with some Lua or assembler sprinkled in. Debugging C++ when your compiler for weird target (SH4, or worse) contains bugs, or when you have some relaxed memory consistency model, is quite a challenge because mapping C++ to assembler is definitely non-trivial. C, even with heavy optimizations, is a breeze comparatively. I would happily join a team that uses Rust in an embedded setting. It shows that they care deeply about doing better than average, and that probably means they are better than average in everything.
- ncmncm 5y agoMapping C++ to assembler is exactly the same as mapping C to assembler, for those operations the languages share. If you are coding reasonably, there aren't any other operations that happen at runtime. C++ does its heavy lifting, preventing bugs, at compile time.
- osivertsson 5y agoFor sure C++ does a lot of heavy lifting at compile time, which shows in poor compile and link times, although it is less of a problem today than 25 years ago since hardware performance has increased. I don’t agree that C++ automatically prevents bugs, even though using e.g. RAII can help a bit and leads to maintainable code. If you use exceptions (you probably shouldn’t) there is one more code-path out from your code. That together with constructors/destructors being called and using STL instead of more trivial data-structures often leads to a lot bigger assembler output to trawl through if you need to.
- ncmncm 5y agoC++ doesn't "automatically" prevent bugs. You have to actually, you know, use it. By STL I guess you mean std::string and std::vector. That is wholly optional. I would not use those in a small embedded project, except maybe at startup, and then with a custom, non-freeing bump allocator.
- dexterhaslem 5y agoin my embedded experience (small scrappy teams in contracting) c99 is just barely common place. and very welcome. 99% covers everything I've done. but for absolutely huge mcus where rust is supported, rust is probably welcome and easier to fit
- adamnemecek 5y ago[2018] but spiritually [1995].
- zabzonk 5y agoSpiritually sometime in the 70s, I would say. Just one example: auto lim = atoi(argv[1]); Use of atoi. And what if there is nothing at argv[1]?
- secondcoming 5y agoIt's just example code.
- zabzonk 5y agoBad example.
- deleted 5y ago[deleted]
- rcurry 5y agoI spent a lot of years writing C++ code and really enjoyed it, it’s a fun language and you can pretty much do anything with it. But the problem I encountered with it was that it just became so wide in terms of features that you have a hard time keeping up - you can spend years using the language to build real software and then walk into a job interview and get demolished by all sorts of crazy stuff you didn’t even know existed. I remember purchasing the book “Modern C++ Design” by Andrei Alexandrescu and after reading it I realized it was time to find something else to do. It was an awesome book and I loved it, but all I did was work on trading systems and I knew I’d never be able to keep up with C++ interviews if that was the direction they’d be taking. But I still love the memories of working with it, so much damned fun.
- bob1029 5y ago> so wide in terms of features that you have a hard time keeping up This is why I like the slightly more walled-in gardens of the JVM and CLR. For instance, when someone is talking about JSON serialization in C#, you could bet your life that they are referring to one of ~2 specific libraries and sets of methods. It is a lot easier to build a community of shared understanding when everyone is playing the same game every day.
- pjmlp 5y ago> For instance, when someone is talking about JSON serialization in C#, you could bet your life that they are referring to one of ~2 specific libraries and sets of methods. I wouldn't bet on it, https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/ https://devblogs.microsoft.com/dotnet/try-the-new-system-tex... Also try to talk about Java 17 to clueless group of devs still delivering stuff into production with Java 8 in 2021.
- vips7L 5y ago> Also try to talk about Java 17 to clueless group of devs still delivering stuff into production with Java 8 in 2021. Id say it’s part cluelessness and it’s part that they just don’t care. They’re comfortable with 8 and don’t want to learn anything new (even if 8 is a slower runtime). I fear that the community will never move on past 8.
- habibur 5y ago> an array of strings is now stored in contiguous memory, which is great for memory cache hitrates, which often delivers whole factors of speedup. How do they do that? As string lengths can vary. One way might be to store the continuous strings in memory and then maintain an array of pointers to those strings. But then we are back to pointers. Searched google. Didn't find anything.
- zabzonk 5y agoThis is not an article written by someone that knows what they are talking about.
- exdsq 5y agoThis is written by Bert Hupert, the founder of PowerDNS among other things. That's at least 20 years of solid C++ engineering work.
- bla3 5y agoIt's called the "short string optimization".
- kjksf 5y agoWhat he meant that if you have an array of strings that implement Small String Optimization AND those strings are short (i.e. below the threshold for Small String Optimization) THEN they'll be contiguous in memory. But you can be smarter than that. As it happens, I just implemented "vector of strings" where all strings are contiguous in memory. The code: https://github.com/sumatrapdfreader/sumatrapdf/commit/bc83112ff0b9607f1155e6b923001f2ea0e0286c#diff-35f8652bb542c1e449b60087a004e5b479a92f3a1f70f748da1fbada6813148eR2704 https://github.com/sumatrapdfreader/sumatrapdf/commit/bc8311... The basic idea is like you said: you keep strings contiguously in memory and maintain a separate array of pointers to each string. Except it's not a pointer but u32 index into that block of memory. Even if those were pointers, not the u32 indexes, it would still be cache friendly. The point is that strings are close together. If each string was allocated with malloc() then you don't control where they are allocated. In the worst case each string could end up in a separate cache line, which would be much slower if you were to iterate over all strings.
- cletus 5y agoHonestly I never want to write C++ again. It's a horrible Frankenlanguage at this point. I wrote C++ for awhile at Google and Google uses a fairly subset of C++: - No exceptions. Instead they had util::Status (open sourced as absl::Status [1]) and a union type util::StatusOr<T>. I don't believe there's a C++ equivalent for this yet. There's a draft proposal for std::expected [2] but it didn't make it into C++20. I'm not sure what the future is. After many years I truly believe exceptions are a false economy for error-handling; 2. Teams can't write their own templates. This is for good reason. There's almost certainly no good reason to do this and you'll probably screw it up what with correctly handling rvalue references (eg perfect forwarding [3]) and the like. 3. No mutable reference parameters. These are really an anti-pattern and can give the caller no clue that something is modified. Worse, if you allow them you'll find people forget to const their references so you don't actually know if they're modified or not. Even worse, the compiler doesn't know either so it limits optimization opportunities. It wasn't perfect. For anyone in the know I'll just say "int/size_t" and leave it at that, as one example. Here are some practical problems: 1. The language is incredibly complex. This makes tooling more difficult. It also means any large C++ shop will out of necessity limit the features allowed such that every shop using a different C++ dialect; 2. As much as we now (since C++11) have smart pointers, you'll still find yourself using raw pointers. You then get into the issues that arise from this, primarily using pointers after their lifetimes and documenting who owns what the pointer points to; 3. The focus on threading primitives. I am now firmly in the camp that if you ever manually create a thread, you've screwed up. The potential pitfalls and errors from doing so are just massive. Most of the time you don't need it either. You should be using higher concurrency primitives or, in a lot of cases, use a cooperative async-await model as you rarely ever need to write truly multithreaded code; 4. (This applies to C too) The fact that types are platform dependent mean you need to use translation layers. So the standards only say a short isn't longer than an int and a long isn't shorter than an int and that's it. 5. Even initializing a variable is complicated [4]; 6. std::string vs char * interfaces. Fun fact: there was a time in Chrome when every keypress on the Omnibar resulted in >25,000 string copies. 7. The ability to use uninitialized memory. 8. Stack vs heap allocation is obviously useful but the complexity cost is just massive. Just look at lambda capture [5]. 7. The learning curve for C++ is just huge and that entails a lot of useless knowledge (eg explicit constructors, default constructors, copy constructors, move constructors, copy constructors vs assignment operators). Almost all the time you don't write code for performance. You write it to work and for the next guy to know what the hell is going on and it's this last one where I think C++ falls so short. I've known too many self-proclaimed C++ experts who revel in the complexity of C++ and consider it a virtue. It's like it allows them to show everyone how smart they are by using some esoteric feature or relying on some non-obvious default (eg a bit like the Javascript semi-colon ASI egoists). I just never want to touch it again. [1]: https://abseil.io/docs/cpp/guides/status https://abseil.io/docs/cpp/guides/status [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r4.html http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p032... [3]: https://eli.thegreenplace.net/2014/perfect-forwarding-and-universal-references-in-c https://eli.thegreenplace.net/2014/perfect-forwarding-and-un... [4]: https://en.cppreference.com/w/cpp/language/initialization https://en.cppreference.com/w/cpp/language/initialization [5]: https://en.cppreference.com/w/cpp/language/lambda https://en.cppreference.com/w/cpp/language/lambda
- beached_whale 5y agoInteresting, the talk to the small buffer optimization is wrong. Only libc++, clangs/llvm's standard library implementation that is used on macos/bsd's, is that large. MS STL and libstdc++ are around 15-16 bytes. Nice property of the libc++ one is that a 64bit integer will fit into it without allocating
- ndesaulniers 5y agolibc++ is the default C++ runtime on Android as well.
- beached_whale 5y agoooh I didn't think of that, thanks. I guess ios too.
- Jedd 5y ago"[C++] certainly has its good points. But by and large I think it's a bad language. It does a lot of things half well and it’s just a garbage heap of ideas that are mutually exclusive. Everybody I know, whether it’s personal or corporate, selects a subset and these subsets are different. So it’s not a good language to transport an algorithm—to say, "I wrote it; here, take it." It’s way too big, way too complex. And it’s obviously built by a committee. "Stroustrup campaigned for years and years and years, way beyond any sort of technical contributions he made to the language, to get it adopted and used. And he sort of ran all the standards committees with a whip and a chair. And he said "no" to no one. He put every feature in that language that ever existed. It wasn't cleanly designed—it was just the union of everything that came along. And I think it suffered drastically from that." -- Ken Thompson, 2009 Source: https://en.wikiquote.org/wiki/Ken_Thompson#%22Coders_At_Work%22,_2009 https://en.wikiquote.org/wiki/Ken_Thompson#%22Coders_At_Work...
- pjmlp 5y agoBjarne's vision for C++ is well documented in "The Design and Evolution of C++". but naturally Ken Thompson is completely unbiased against C++, just like Linus Torvalds. https://www.amazon.de/-/en/Bjarne-Stroustrup/dp/0201543303 https://www.amazon.de/-/en/Bjarne-Stroustrup/dp/0201543303
- hdjjhhvvhga 5y agoRather than resorting to ad hominem, could you point out where exactly Thompson was actually wrong? Moreover, the criticism by Thompson and Torvalds refers to the use of C++ as a systems programming language. The language proved itself very efficient for application programming, including the browsers everybody is using.
- pjmlp 5y agoKen Thomson had no issues doing that when referring to Bjarne Stroustroup. He is completely wrong, because his comments reveals a complete lack of understanding how ISO works, or worse, he does understand it and is doing a malicious comment to transmit his biased opinion. Bjarne has the vote of one person, it doesn't matter how much he yells, screams, slashes the whip down the members back. It is one single vote, and above all, unless he has some dark magic powers, he cannot multiply himself to attend all voting sessions.
- posharma 5y ago“There are only two kinds of languages: the ones people complain about and the ones nobody uses.”
- nazrulmum10 5y agoIt may be hard to believe, but for much of the time of C++’s original development, it did not have a string class. Writing such a class was somewhat of a rite of passage, and everyone made their own. The reason behind this was partially the prolonged attempt to make a class that was everything for everyone.
- flohofwoe 5y agoThe qsort() performance example in the beginning is a bit misleading. If you give the C compiler enough information (for instance an inline-able implementation of qsort()) then the compiler will happily "disolve" the comparison callback and custom types into a specialized "stamped out" version of qsort, just like std::qsort(). No fancy template magic needed for that, just an optimizing compiler. The only difference between the two is that the C++ qsort implementation lives as inline code in a header file, while C's qsort lives "out of reach" in the C runtime library. If C's qsort implementation is in the same compilation unit (or LTO is used), a C compiler has the same optimization opportunities as C++. For example here's a C qsort example where the compiler can see the qsort implementation (using an inline copy of MUSL's qsort). Note in the assembly window how the comparison callbacks have disappeared completely, this is basically C's version of "zero cost abstractions" (which really is just a fancy name for "compiler optimization passes", which isn't unique to C++): https://www.godbolt.org/z/Mn4PfE9q7 https://www.godbolt.org/z/Mn4PfE9q7
- account42 5y agoFirst of all, qsort in C is not in-lineable and not even visible with LTO since it tends to be implemented in the C library while std::sort is always visible. Yes you can bring your own qsort, but that misses the point - you could just manually inline the comparison function at that point. Secondly. std::sort is a template with the type of the comparator being a template parameter. This means that if you use a lambda or functor as the comparator, the template will create a std::sort instance that always calls that comparater and the decision to inline the comparator is relatively simple. In controst, for the qsort example the compiler will need to either inline the whole qsort at the call site (which happens in your example) or create a specialized copy of the qsort function for your comparator. If you switch the compiler to GCC neither happens in this case (it does specialize it for some of the other parameters, but not the comparison function).
- Zababa 5y agoFrom the intro: "2018 is an exciting time to be a programmer, with so many good “full service” programming languages to choose from: C, C++ 2017, Go, Python, Rust and who knows Swift too.". What does the author means by "full service" here?