I spend most of my time writing C code for STM32 microcontrollers. I have recently considered writing more code in C++, mainly for easier implementation of various design patterns and especially for using abstract classes for dependency injection when writing testable modules/classes.
However, when using STM32CubeMX to generate hardware initialization code, there is no option to use C++ instead of C. Mostly this is not a concern, since nearly all C code is also valid C++ code, so there is no problem including the generated C code in your C++ application code. However, CubeMX also generates a main.c
file where all the hardware initialization functions are called. Since we might want to add some additional initialization code in C++, we would rather have a main.cpp
file. You can try simply renaming the file, but the next time you make any changes in CubeMX and run the code generator, a new main.c
file will be generated and main.cpp
will remain untouched.
I have seen people suggest renaming main.cpp
to main.c
before generating code and then renaming it back to main.cpp
afterwards, which doesn’t seem like a sustainable solution. Below I’ll present a simple workaround.
Create a C++ project or convert an existing C project in STM32CubeIDE
Create a new STM32 project by navigating to File > New > STM32 Project. Select your desired MCU or development board. When you get to the following screen, make sure to select C++ as the targeted language:

If you have an existing C project that you want to convert to C++, right click your project in the Project Explorer and select “Convert to C++”:

As far as I can tell, this simply adds the g++ compiler to your project toolchain.
After creating the project you will notice that a main.c
file has been generated instead of main.cpp
:

Instead of the silly renaming before and after running CubeMX, a simple workaround is to create an alternate main function in C++ but with C calling convention. Let’s name it alt_main(). We can then call this function from main.c
inside a USER CODE BLOCK
. This way CubeMX can still generate code in main.c
, but you can use the alt_main()
function as the entry point for your C++ application.
An alternate main() function
First we will create the header file for our alternate main function:
#ifndef ALT_MAIN_H_
#define ALT_MAIN_H_
#ifdef __cplusplus
extern "C"
{
#endif
int alt_main();
#ifdef __cplusplus
}
#endif
#endif
If we include the header from a C++ file, we see that the function declaration gets wrapped in an extern "C"
block, ensuring that the function is called using C calling convention. If we include it from a C file, it just looks like a regular C function.
Next we will create the source file:
#include "alt_main.h"
int alt_main()
{
/* Initialization */
while (1)
{
/* Super loop */
}
}
Notice that this is a .cpp
file, so we can write all the C++ code we want in here.
Next, we will call alt_main()
from within a USER CODE BLOCK
in main()
before the super loop:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
alt_main(); // Contains our super loop, so the while loop below will never be executed
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
That’s it! Now you can just let CubeMX handle main.c
and you can add your own code in alt_main.cpp
.
Using the global peripheral handles
Lastly, if you are using the default CubeMX settings, all handles for the initialized peripherals will be defined globally in main.c
. For example, if you initialize SPI1 in CubeMX, SPI_HandleTypeDef hspi1
will appear in the “Private variables” section in main.c
. If you want to use this handle in alt_main.cpp
, you’ll have to declare it extern
in that file. This gets a bit messy if you have a lot of peripherals.
Instead, you can configure CubeMX to generate a separate header and source file for each type of peripheral. In CubeMX go to Project Manager > Code Generator and check the box “Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral“:

Now you can simply #include "spi.h"
where all SPI handles are declared.
Thank you very much, it helped.
Especially the “Convert to C++” and the idea to run my alternate main().
I’m glad to hear you found it useful.
Hi! Every .cpp file is compiled using g++. There is a way to switch compiler to main.c file so it will be treated as .cpp file.
Right click on main.c -> Properties -> C/C++ Build -> Settings-> Command. Instead of gcc use g++
Check last comment https://shawnhymel.com/1941/how-to-use-c-with-stm32cubeide/