Using classes/objects with CubeMX project
Dude (hardwareguyvw), C++ is C; just better Some of us have been using it in embedded code for a while now...
jrhansen : there are a few things you’ll need to brush up on as you are working at a slightly lower level than for example writing a C++ app on Linux.
You need to go and read about “C++ name mangling” and how the C++ compiler creates type safe linkage and how that affects linking to C code. Note in the example below how extern "C"
is used to give C linkage to a C++ function and how a combination of that and #ifdef __cplusplus
is used to maintain it if a header is included in C++ that has C functions. Note that the HAL libraries all have this construct already.
You should name your files appropriately so you keep everything straight - so that’s “.cpp” for your C++ source and “.c” for the plain C source. Try not to mix those as you’ll be in trouble.
I’m assuming that’s where your Eclipse says: unknown type name ‘class’
error came from.
Also, while not strictly required, name your C++ headers “.hpp” or something - it’ll help to not include C++ headers in C source (the reverse is easily dealt with - see #ifdef __cplusplus
).
As for “calling through” to C++ code from (for example) the CubeMX generated output, you’ll need to make C++ functions with C naming conventions - here’s a simple approach that works fine for a project that you’re reworking from CubeMX side regularly and yet using C++.
Basically you have a C header that you include in the CubeMX main which declares C functions to call from there:
/** @file fred.h
* ie: this is a C lang header
*/
#ifndef APP_FRED_H_
#define APP_FRED_H_
#ifdef __cplusplus
extern "C" {
#endif
//! insert call to this function from CubeMX generated init
void Fred_init();
//! insert call to this function from CubeMX generated loop
void Fred_loop();
#ifdef __cplusplus
}
#endif // __cplusplus
#endif /* APP_FRED_H_ */
You have your C++ headers for declaration of your own stuff:
/** @file Fred.private.hpp
* ie: C++ header file
*/
#ifndef APP_FRED_PRIVATE_HPP_
#define APP_FRED_PRIVATE_HPP_
#include <cstdint> // ie: can include std lib headers
#include <cstddef>
#include "main.h" // ie: safe to include CubeMX C code headers
#include "gpio.h"
/** wrapper class for "application"
*
*/
class Fred
{
private:
//! application singleton - be aware of static initialisation timing & limitations in embedded context etc
static Fred instance;
public:
//! bootstrap C code into C++ class instance init method
static inline void call_init() { instance.init(); }
//! bootstrap C code into C++ class instance loop method
static inline void call_loop() { instance.loop(); }
Fred();
//! initialise application
void init();
//! do application superloop
void loop();
};
#endif /* APP_FRED_PRIVATE_HPP_ */
and then you define that function in a C++ source file (where you get C++ linkage):
/** @file Fred.cpp
* ie: a C++ source file
*/
#include "Fred.private.hpp"
#include "Fred.h"
extern "C" void Fred_init() { Fred::call_init(); }
extern "C" void Fred_loop() { Fred::call_loop(); }
//rest of Fred class definitions go here
Be Aware that you really need to understand the C++ object lifecycle, when are where static initialisation occurs and exactly how much stack space you can blow using some of the fancier STL stuff that does a lot of copies.
Learn about all the good keywords like ‘explicit’ and ‘const’ and how they save you extra copies and make life a bit safer in an embedded context.
There are some pretty good resources out there on the generic concepts involved in calling C from C++ or vice versa.
Oh, and the “weak” linkage functions that HAL provides for various things are also usable from the C++ side if you remember to do the extern C dance.