Takeaway #1: "C and C++ are different: don’t mix them, and don’t mix them up"
This is how I managed to sneak C++ into an embedded C codebase. We even created some templates for data structures that supported static allocation at compile time.
https://herbsutter.com/2012/05/03/reader-qa-what-about-vc-an...
I guess what you're really asking is what are the best or most common ways to do OO in C?
Another big one that I always forget C still doesn't support is function overloading.
Where can I find something about objects being "think of your code as representing the state and interactions of objects" honesty totally new to me.
So no, certainly I'm not asking ways to do OO in C. But it seems to be more definitions of object orientation as I thought...
Yes you can do it less cleanly with macros or inline functions. But you can't do it performantly with struct and function pointers.
C++ imo doesn't offer anything compelling for the embedded usecase. Especially not considering all the footguns and politics it brings.
You can of course be strict and diligent about it but if you are you are pretty much just writing C anyway. Better to do it explicitly.
Allowing the use of the C++ standard library has been one of my biggest regrets (not that it was my decision to make, I fought it).
But why would you do that if you have an instrument that lets you work at the same level as C, but with methods provided as a proper abstraction that maps exactly to what you'd have written yourself anyway?
If you do that, you'll notice that, for example, encapsulation is not a part of that de facto definition, because languages like Python and (until recently) JavaScript lack it, despite being considered OO.
Indeed, the only two things that appear to be consistently present in all OO languages are: 1) some notion of object identity as distinct from object state, and 2) runtime polymorphic dispatch.
> it is hard to say no to you, and I’m sorry to say it. But we have to choose a focus, and our focus is to implement (the standard) and innovate (with extensions like everyone but which we also contribute for potential standardization) in C++.
I mean, yeah if it came from a two member team at a startup, sure focus on C++, understandably. But Microsoft, what happened to "Developers! Developers! Developers!"?
I’m scratching my head how you think this is materially different than what you described in your first para. s/state/data and s/interactions/methods.
If anything though I would say the GP is more aligned with the classic definition as it highlights the focus is more on the messages (interactions) themselves rather than the implementation.
There's an effort to extract the good parts and make it work for embedded use cases or even bring them into C. Khalil Estelle on WG21 has been working on an experimental, deterministic runtime for exception handling, to give one example. Constexpr is an example of the latter that's now showing up in C23.
One of the most compelling things C++ offers to embedded use case is moving runtime initialization to compile-time initialization by liberally using constexpr functions. You literally ask the compiler to do work that would otherwise be done at runtime.
Indeed, and yet here we are with C23
> The change of heart was the new management, and the whole Microsoft <3 FOSS.
Yeah, agree. To me the turning point was when they created WSL.
But without exceptions it is mostly syntactic sugar anyway.
If compile time initialization is the most compelling usecase I'll rest my case. Good feature, yes! Hardly worth switching language for.
But having the "class" keyword is nice. Having built in support for member functions is nice.
Sometimes a person just wants the simplicity of C++ 2003.
(In reality I was working on a project where our compiler only supported C++ 2003 and we had a UI library written in C++ 2003 and honestly pure C UI libraries kind of suck compared to just sprinkling in a bit of C++ sugar.)
> You can do anything in C that you want to.
How about destructors?Though I've actually seen macro systems that do things akin to destructors, although less automatically.
This is no longer true. On UEFI systems the only thing you have to do normally is fix the boot order. In fact installing Linux first and Windows second tends to be the better dual-boot strategy nowadays.
Fixing the boot order can be done from UEFI setup, and even from Windows command line
bcdedit /enum firmware
bcdedit /set {fwbootmgr} displayorder {yourlinuxuuid} /addfirst
(Put single quotes around {} if you use PowerShell instead of CMD.exe) template<typename R>
constexpr ssize_t
io::ReadFull(R reader, char *buf, size_t len)
{
ssize_t recvd = 0, ret;
do {
ret = read(reader, &buf[recvd], len - recvd);
if (ret > 0)
recvd += ret;
else
break;
} while (recvd < len);
return recvd;
}
---1: https://open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3980.h...
One exception to that in my experience: dependencies, although I think that's a bit deceiving as yes, it's easier to get dependencies in Rust but in some areas they're way less mature and can sometimes be a pain to work with (usually when dealing with big C or C++ libraries that have been quickly glued to a Rust interface to be available in Rust).
And not being competent in C++ is not great. You are going to be much more productive in C. The feedback loop is much faster, that is, feedback from your designs.
Contrast with Rust which is harder to get going but doesn't require nearly as much to be decent.
And no, you don't have to put everything in the header with C++, and especially not if you're using it in "C with classes" mode. C++ only needs it for templates - and even then only if you want to use implicit instantiation, with `extern template` available for fine-grained control allowing you to have those specializations separately compiled and implementations kept out of the header file.