News for hackers. Stuff that matters.
Re:Practical Guide to Bare Metal C++ by myrmidon on Tuesday March 10, 2026 @09:03AM (#47322726)
> There are multiple articles of how C++ is superior to C, that everything you can do in C you can do in C++ with a lot of extras, and that it should be used even with bare metal development

An interesting perspective. Could turn it around as "everything you can do in C++ you can do in C with a lot less language complexity".

My personal experience with low-level embedded code is that C++ is rarely all that helpful, tends to bait you into abstractions that don't really help, brings additional linker/compiler/toolchain complexity and often needs significant extra work because you can't really leverage it without building C++ abstractions over provided C-apis/register definitions.

Would not generally recommend.

Re:Practical Guide to Bare Metal C++ by kryptiskt on Tuesday March 10, 2026 @10:59AM (#47324178)
> Could turn it around as "everything you can do in C++ you can do in C with a lot less language complexity".

No, you can't, C is lacking a lot that C++ brings to the table. C++ has abstraction capabilities with generic programming and, dare I say it, OO that C has no substitute for. C++ has compile-time computation facilities that C has no substitute for.

Re:Practical Guide to Bare Metal C++ by myrmidon on Tuesday March 10, 2026 @12:08PM (#47325160)
My point is trivially true as far as computability goes, but that is not what I ment.

All those abstraction capabilities can be a big detriment to any project, because they always come with a cost, and runtime is far from the only concern.

Specifically in an embedded project, toolchain complications and memory use (both RAM and code) are potentially much bigger concerns than for Desktop applications, and your selection of programmers is more limited as well; might be much more feasible to lock your developers onto acceptable C coding standards than to make e.g. "template metaprogramming" a necessary prerequisite for your codebase and then having to teach your applicants electrical engineering.

Both object oriented programming and compile time computation is doable for a C codebase, just needs more boilerplate and maybe a code-generator step in your build, respectively. But that might well be an advantage, discouraging frivolous use of complexity that you don't actually need, and that introduces hidden costs (understanding, ease of change, compile time) elsewhere.

Re:Practical Guide to Bare Metal C++ by embeng4096 on Tuesday March 10, 2026 @11:50AM (#47324907)
Is there an example of the generic programming that you've found useful?

The extent of my experience has been being able to replace functions like convert_uint32_to_float and convert_uint32_to_int32 by using templates to something like convert_uint32<float>(input_value), and I didn't feel like I really got much value out of that.

My team has also been using CRTP for static polymorphism, but I also feel like I haven't gotten much more value out of having e.g. a Thread base class and a derived class from that that implements a task function versus just writing a task function and passing it xTaskCreate (FreeRTOS) or tx_thread_create (ThreadX).

Typed compile-time computation is nice, though, good point. constexpr and such versus untyped #define macros.

Re:Practical Guide to Bare Metal C++ by slaymaker1907 on Tuesday March 10, 2026 @12:26PM (#47325411)
std::array can sometimes give you the best of both worlds for stack allocation in that you statically constrain the stack allocation size (no alloca) while guaranteeing that your buffers are large enough for your data. You can also do a lot of powerful things with constexpr that are just not possible with arrays. It is very convenient for maintaining static mappings from enums to some other values.
Re:Practical Guide to Bare Metal C++ by csb6 on Tuesday March 10, 2026 @01:06PM (#47326014)
The generic algorithms that come with the C++ standard library are useful. Once you get used to using them you start to see that ad-hoc implementations of many of them get written repeatedly in most code. Since most of the algorithms work on plain arrays as well as more complex containers they are still useful in embedded environments.
Re:Practical Guide to Bare Metal C++ by CyberDildonics on Tuesday March 10, 2026 @03:02PM (#47327484)
You've never used a template for a data structure and you've never used a destructor to free memory?
Re:Practical Guide to Bare Metal C++ by rkagerer on Tuesday March 10, 2026 @10:18PM (#47331122)
I had been programming for a long time before I learned OOP. After some years playing with it, I came to the conclusion there's not much I can't do about as well using simple functions and structs. The key is a well thought out and organized codebase. Always felt polymorphism in particular seemed more trouble than it was worth.

I still use modern languages on a regular basis, but when I drop back to more basic languages there are only a few ergonomics that I truly miss (eg. generics).

Re:Practical Guide to Bare Metal C++ by jonathrg on Wednesday March 11, 2026 @12:04PM (#47337384)
Having a type safe generic ring buffer and such is nice
Re:Practical Guide to Bare Metal C++ by bigfishrunning on Tuesday March 10, 2026 @03:57PM (#47328046)
> C++ has compile-time computation facilities that C has no substitute for.

The substitute for this is that C is insanely easy to generate. Do your compile time computation in your build system.

OO is also pretty trivial in C -- the Linux kernel is a great example of a program in C this is very Object Oriented.

Re:Practical Guide to Bare Metal C++ by jonathrg on Tuesday March 10, 2026 @09:11AM (#47322823)
You definitely need discipline to use C++ in embedded. There are exactly 2 features that come to mind, which makes it worth it for me: 1) replacing complex macros or duplicated code with simple templates, and 2) RAII for critical sections or other kinds of locks.
Re:Practical Guide to Bare Metal C++ by kevin_thibedeau on Tuesday March 10, 2026 @02:37PM (#47327151)
Consteval is great for generating lookup tables without external code generators. You can use floating point freely, cast the result to integers, and then not link any soft float code into the final binary.
Re:Practical Guide to Bare Metal C++ by g947o on Tuesday March 10, 2026 @09:07AM (#47322766)
Mind if I ask whether you speak of that from a professional embedded system engineer's perspective?
Re:Practical Guide to Bare Metal C++ by myrmidon on Tuesday March 10, 2026 @09:17AM (#47322879)
I do. But talking about low-level embedded stuff here.

Generally, the more you deviate from your vendors "happy path", the more busy work/unexpected difficulties you will run into, and a solid grasp of how exactly architecture and toolchain work might become necessary (while staying on the "happy path" allows you to stay blissfully unaware).

Re:Practical Guide to Bare Metal C++ by embeng4096 on Tuesday March 10, 2026 @10:33AM (#47323839)
+1 to this and your above points (the embedded team I'm on has started using C++ over the last year or so).

I've definitely learned a lot, and I like the portability of CMake for cross-platform use (our team uses all 3 of Windows, Mac, and Linux). My experience sounds much like yours: there've been a lot of times where using the vendor's flavor of Eclipse-based IDE (STM32CubeIDE, Renesas e2studio, etc) would have saved us a lot of discovered work, or extra work adapting the "happy path" to CMake and/or C++.

Using C++ and/or CMake is fine when it's part of the happy path and for simpler things e.g. STM32CubeMX-generated CMake project + simple usage of HAL. For more complex things like including MCUboot or SBSFU, etc, it's forced me to really dig in. Or even just including FreeRTOS/ThreadX, we've created abstractions like a Thread class on top -- sometimes it's nice and convenient, others it feels like unnecessary complexity, but maybe I'm just not used to C++ yet.

One clear, simple example is needing to figure out CMake and Ninja install. In an Eclipse-based IDE, you install the platform and everything Just Works(tm). I eventually landed on using scoop to install CMake and Ninja, which was an easy solution and didn't require editing my PATH, etc, but that wasn't the first thing I tried.

Re:Practical Guide to Bare Metal C++ by adrian_b on Tuesday March 10, 2026 @04:26PM (#47328391)
I have never seen any advantage of CMake over the much simpler GNU make.

Ninja is supposed to be faster for compiling very big software projects, but I have never seen an embedded software project that is well organized and which is not compiled in a few seconds on a powerful development computer with many cores, so I do not see the benefit of Ninja for such projects.

All Eclipse-based IDEs that I have ever seen are extremely slow for anything, both for editing and for building a project and they make the simplest project management operations extremely complicated. Even Visual Code Studio is much faster and more convenient than using Eclipse-based IDEs. Other solutions can be much faster.

While the example programs provided for STM32 MCUs are extremely useful for starting a project for them, I believe that using the methods of project building provided by the vendor results in a waste of time. I have always obtained better results and faster development by building a GNU toolchain (e.g. binutils,gcc,gdb, some libc) from scratch and by using universal GNU makefiles, which work for any CPU target and for any software project, with the customization of a few Make variables. I have written once a set of GNU Makefiles, according to its manual, around 1998, and I have never had to change them since then, regardless what platform I had as a target. For any new platform, there is just a small set of variables that must be changed by generating one per-platform included file, with things like the names of the compilers and other tools that must be invoked and their command-line options.

For new projects, there is one very small file that must be generated for each binary file that must be built, which must contain the type of the file (e.g. executable, static library, shared library) and a list with one or more directories where source files should be searched. No changes are needed when source files are created, deleted, moved or renamed, and dependencies are identified automatically. I am always astonished when I see how many totally unnecessary complications exist in the majority of the project building configurations that I have ever seen provided by the vendors or in most open-source projects.

Re:Practical Guide to Bare Metal C++ by chris_money202 on Wednesday March 11, 2026 @04:51AM (#47333156)
Just switched one of my teams firmware projects from make to cmake + ninja (with the help of GHCP). Build time went from 10 minutes to 2 minutes and now we have ability just to build what has changed.
Re:Practical Guide to Bare Metal C++ by myrmidon on Wednesday March 11, 2026 @05:11AM (#47333310)
You might have just had a bad makefile.

The "canonical" way to just build what was changed with make is to let the compiler generate header dependencies during the build and to include those (=> if you change only 1 header, just the affected translation units get rebuilt). Works like a charm (and never messes up incremental builds by not rebuilding on a header-only change).

If you did not have proper incremental builds before, I would blame the makefile specifically and not make itself.

Another way to mess up with make is to not allow anything in parallel, either by missing flags (-j) or by having a rule that does everything sequentially.

Ninja does have less overhead than make, but your build time should be dominated by how long compiler and linker take; such a big difference between the two indicates to me that your old make setup was broken in some way.

Re:Practical Guide to Bare Metal C++ by chris_money202 on Wednesday March 11, 2026 @09:43AM (#47335478)
It definitely was but that’s the issue with make, it allows for that sloppyness to enter the build system much easier. Cmake gives some rigidity and reuse to shield the casual dev from mucking up the build definition. You can probably do same things with make and cmake, it’s like a C vs C++ argument. And what I say to that is usually just do what you prefer to use and maintain
Re:Practical Guide to Bare Metal C++ by technothrasher on Tuesday March 10, 2026 @09:25AM (#47322952)
I struggle with this deviating from the vendor's "happy path" often. I mostly use the STM32 chips, and I don't particularly care for their HAL library. I find it over complicated and often has bugs in it that I have to track down and fix. But boy is it nice to use their STM32CubeMX program to generate all the low level code so I can just get to work. I tend to end up building my own low level libraries during my free time because I enjoy it and it gives me a better idea of how the hardware is actually working, but using the STM32 HAL library to write my actual client code at work.
Re:Practical Guide to Bare Metal C++ by patchnull on Tuesday March 10, 2026 @11:08AM (#47324315)
Same experience here. What worked for me was using CubeMX purely for pin and clock config, then dropping down to the LL (low-layer) drivers or direct CMSIS register access for anything in a hot path. The HAL interrupt handlers in particular add a surprising amount of overhead — on a tight DMA transfer loop I measured ~40% cycle waste just from HAL callback dispatch.

The LL API is basically thin inline wrappers around register writes, so you still get the CubeMX-generated init code but without the HAL abstraction tax at runtime.

Re:Practical Guide to Bare Metal C++ by bsoles on Tuesday March 10, 2026 @10:26PM (#47331155)
Also same experience here. I can write UART code with DMA in 20 lines of code on an STM32 microcontroller. Same functionality using HAL is astonishingly cumbersome. The reference manual and willingness to read it is all you need.
Re:Practical Guide to Bare Metal C++ by myrmidon on Wednesday March 11, 2026 @08:05AM (#47334518)
To be fair: If you fully rely on the ST tooling, setting up even something moderately complex, peripheral wise (like a bidirectional UART <=> USB bridge) is very straightforward because you get all the configuration/software stack just from clicking a few things in their GUI tool, then write a few lines of API calls and you're done. It's gonna be neither pretty nor especially efficient (specifically STs default HAL interrupt routines tend to be atrociously wasteful), but chances are good that it actually works immediately.

But if you want to do that from scratch with little experience, you are almost invariably gonna miss like 5 different clock/IRQ/peripheral enable flags, get some clock prescaler wrong, missconfigure a GPIO pin or two and then spend a bunch of time tracking things down with debugger, reference manual and scope...

Re:Practical Guide to Bare Metal C++ by Conscat on Tuesday March 10, 2026 @01:59PM (#47326677)
> An interesting perspective. Could turn it around as "everything you can do in C++ you can do in C with a lot less language complexity".

C can't parameterize an optimal layout fixed-length bitset with zero overhead, nor can it pragmatically union error sets at scale.

Re:Practical Guide to Bare Metal C++ by bigfishrunning on Tuesday March 10, 2026 @03:50PM (#47327974)
I would honestly extend this sentiment out to all code. The benefits C++ has over C are much better served by Rust or Go or Python or Lisp, and if "Simple" is what you want, then C is a much better choice.

Honestly, I can't think of a single job for which C++ is the best tool.

Re:Practical Guide to Bare Metal C++ by chris_money202 on Tuesday March 10, 2026 @09:36PM (#47330891)
With anything low level you should choose the language you’re most comfortable and competent in imo. Learning both the platform and the language is just asking for headaches, control what you can
Re:Practical Guide to Bare Metal C++ by bsoles on Tuesday March 10, 2026 @10:18PM (#47331123)
I find that encapsulation of devices (UART, I2C, etc.) as classes in C++ rather than global functions that take structs, etc. as input arguments in C to be much more manageable. Same for device drivers for individual sensor ICs.
Re:Practical Guide to Bare Metal C++ by myrmidon on Tuesday March 10, 2026 @10:45PM (#47331243)
Maybe, but I'd argue that this is a matter of taste, and what does it actually do for you?

In practice: Is it worth wrapping all your vendor-provided hardware abstraction in classes that you write yourself? Designing something like that to be "complete" (i.e. allow full access to all hardware functionality like IRQ/DMA setup) and to still stay hardware-independent is often borderline impossible anyway, and any attempt is invariably going to make your codebase more difficult to understand.