Skip to main content
Associate III
February 5, 2026
Question

Why we need C++ for modern hardware

  • February 5, 2026
  • 5 replies
  • 584 views

Modern microcontrollers have a lot of perifhery. Several buses of different types.

STM32 hardware has outgrown C. Too much complex perifhery to manage with procedural language.

ST software is much behind of ST hardware.

 

Look at any I2C or SPI open source C library. Any can be used with one device of some type only.

In case of I2C there are lines like this in header:

#define SSD1306_I2C_PORT hi2c1

#define SSD1306_I2C_ADDR (0x3C << 1)

and

extern I2C_HandleTypeDef SSD1306_I2C_PORT;

in C file.

If somebody need one device on differnt port or on different device address he have to edit source files of library.

If somebody need more devices of the same type on different device addresses and/or on different ports, he have to throw away library and write own solution.

It is not possible to get library and make something like this:

i2c_device1 = create_i2c_device(port1, dev_adr1, params1...);

i2c_device2 = create_i2c_device(port1, dev_adr2, params2...);

i2c_device3 = create_i2c_device(port2, dev_adr3, params3...);

 

It's impossible to use two OLED i2c displyas with open source C libraries. It's inacceptable.

I convert C library to C++ and can use

 ssd1306cpp oled1
 { &hi2c1, dev1_adr, disp1_buf, disp1_w, disp1_h, buf1_sz };

 ssd1306cpp oled2
 { &hi2c2, dev2_adr, disp2_buf, disp2_w, disp2_h, buf2_sz };

We definitly need C++ to manage great ST hardware.

 

5 replies

TDK
Super User
February 5, 2026

Related/duplicate:

Generation code to CPP files - STMicroelectronics Community

 

> It's impossible to use two OLED i2c displyas with open source C libraries.

Huh? I do that. It's working okay for me.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Andrew Neil
Super User
February 6, 2026

LOL!

You've been ranting on about how "terrible" CubeMX-generated initialisation code is because it creates loads of structs with runtime initialisations.

So how, exactly, do you think stuff like this is achieved by C++ ?!

 


@vybor wrote:
 

It is not possible to get library and make something like this:

i2c_device1 = create_i2c_device(port1, dev_adr1, params1...);

i2c_device2 = create_i2c_device(port1, dev_adr2, params2...);

i2c_device3 = create_i2c_device(port2, dev_adr3, params3...);

Of course it's possible !

C++ has some features to make it more convenient, but it's certainly possible to do it in C.

If a particular library doesn't allow it, that's a limitation of the library - nothing to do with the fact that it's written in C.

 


@vybor wrote:

In case of I2C there are lines like this in header:

#define SSD1306_I2C_PORT hi2c1

#define SSD1306_I2C_ADDR (0x3C << 1)

Those things should never be part of the library - they would be part of the user's code.

Those would be the parameters that would be passed to your create_i2c_device() function in the user's instanciation(s).

Again, that's a limitation of the library - not a limitation of C.

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Lead II
February 6, 2026

I partially agree.

In C you can write object oriented code. Just not with the same syntax, compile checks and runtime features as C++. In the past I have written C++ wrappers for HAL drivers. So you can combine both C and C++.

Modern C++ adds features that are more useful than objects imho. Such as templates, constexpr etc.
This let's you can let the compiler do compile time checks and calculations. It also significantly reduces reliance on macros. Namespaces also help make names shorter.
But for my applications 90% of my code is functional.

The generated code of ST has some shortcomings:

  • lack of user context in callback functions, means you need to create your own mapping logic: https://community.st.com/t5/stm32-mcus-embedded-software/user-defined-context-in-hal-callbacks/m-p/783093
  • only 1 configuration instead of multiple, makes board version dependent code harder to write
  • no option to dynamically configure hardware runtime, init functions are generated and optmized, but if you want more flexibility you need to rewrite the code. For instance deinitializing a GPIO pin could also deinit the gpio clock if that clock is no longer used for any pin to save power. If you want this behavior you need to write it yourself.

 

 

 

 

"Kudo posts if you have the same problem and kudo replies if the solution works.Click ""Accept as Solution"" if a reply solved your problem. If no solution was posted please answer with your own."
Andrew Neil
Super User
February 6, 2026

@unsigned_char_array wrote:

The generated code of ST has some shortcomings:


Indeed. But these have nothing to do with being written in C rather than C++

 


@unsigned_char_array wrote:

Modern C++ adds features that are more useful than objects imho.


Indeed - no argument that C++ has benefits.

But for @vybor to say that it's essential is just not true.

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
TDK
Super User
February 6, 2026

It's fine to have preferences. I prefer C++ as well. But it's another thing to come into an established architecture and system and want the world to change for your desires. Unless you have considerable resources, you don't get to do that, you only get to use what is available.

Is namespace::function better than namespace_function? What makes one uglier than the other?

> If one needs several divices of one type he must to reimplement C++ functionality with restricted C compiler.

Again, this is simply not true. A long time ago there was (and still is) https://stm32f4-discovery.net/about/ which managed to work with multiple peripherals, all using C code. All before HAL and the Cube microsystem. Not to mention HAL is obviously set up to work with multiple peripherals at once.

IRQ handlers get called with no context. Any OOP solution still needs to manage that using plain C. Apart from that, most things are amenable to a C++ implementation.

"If you feel a post has answered your question, please click ""Accept as Solution""."
vyborAuthor
Associate III
February 6, 2026

But these have nothing to do with being written in assembler rather than C

Lead II
February 6, 2026

@vybor wrote:

But these have nothing to do with being written in assembler rather than C


?

"Kudo posts if you have the same problem and kudo replies if the solution works.Click ""Accept as Solution"" if a reply solved your problem. If no solution was posted please answer with your own."