| ▲ | myrmidon 3 hours ago |
| > 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. |
|
| ▲ | kryptiskt an hour ago | parent | next [-] |
| > 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. |
| |
| ▲ | embeng4096 7 minutes ago | parent [-] | | 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. |
|
|
| ▲ | jonathrg 3 hours ago | parent | prev | next [-] |
| 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. |
|
| ▲ | g947o 3 hours ago | parent | prev [-] |
| Mind if I ask whether you speak of that from a professional embedded system engineer's perspective? |
| |
| ▲ | myrmidon 3 hours ago | parent [-] | | 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). | | |
| ▲ | embeng4096 an hour ago | parent | next [-] | | +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. | |
| ▲ | technothrasher 3 hours ago | parent | prev [-] | | 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. | | |
| ▲ | patchnull an hour ago | parent [-] | | 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. |
|
|
|