What's the closest thing to anonymous function pointers I can achieve that compiles with GCC?
-
I am writing code for an ARM processor and compiling with GCC. I have done some C# programming and there you're allowed to declare delegates inside structures. What's the closest thing I can achieve the same thing in my ARM-project? For example, it would great if I could write a state machine like this:
typedef void (*readDataResultCallback_t)(uint8_t* readData, uint16_t sizeOfReadData);
typedef enum {
STATE1 = 0,
STATE2 = 1,
STATE3 = 2,
} stateMachineState_e;typedef struct __attribute__((__packed__)) {
stateMachineState_e state;
uint32_t startAddr;
uint16_t numRegsToRead;
readDataResultCallback_t readDataResultCallback;
} stateMachineStep_s;static stateMachineState_e state = STATE1;
stateMachineStep_s stateMachineSteps[3] = {
{STATE1, 10, 2, { (uint8_t* readData, uint16_t sizeOfReadData) {
if (stringCompare(readData, "AB") {
... Do stuff here...
state = STATE_2;
} else {
... Do stuff here...
state = STATE_3;
}}},
{STATE2, 20, 3, { (uint8_t* readData, uint16_t sizeOfReadData) {
if (stringCompare(readData, "ABC") {
... Do stuff here...
state = STATE_1;
} else {
... Do stuff here...
state = STATE_3;
}}},
{STATE3, 30, 4, { (uint8_t* readData, uint16_t sizeOfReadData) {
if (stringCompare(readData, "ABCD") {
... Do stuff here...
state = STATE_3;
} else {
... Do stuff here...
state = STATE_2;
}}},
};Do I need to write my own pre-compile code interpreter/generator script that would place the anonymous code in functions outside the stateMachineStep_s array or is there something clever I can do (perhaps with macros or C++)?
-
I am writing code for an ARM processor and compiling with GCC. I have done some C# programming and there you're allowed to declare delegates inside structures. What's the closest thing I can achieve the same thing in my ARM-project? For example, it would great if I could write a state machine like this:
typedef void (*readDataResultCallback_t)(uint8_t* readData, uint16_t sizeOfReadData);
typedef enum {
STATE1 = 0,
STATE2 = 1,
STATE3 = 2,
} stateMachineState_e;typedef struct __attribute__((__packed__)) {
stateMachineState_e state;
uint32_t startAddr;
uint16_t numRegsToRead;
readDataResultCallback_t readDataResultCallback;
} stateMachineStep_s;static stateMachineState_e state = STATE1;
stateMachineStep_s stateMachineSteps[3] = {
{STATE1, 10, 2, { (uint8_t* readData, uint16_t sizeOfReadData) {
if (stringCompare(readData, "AB") {
... Do stuff here...
state = STATE_2;
} else {
... Do stuff here...
state = STATE_3;
}}},
{STATE2, 20, 3, { (uint8_t* readData, uint16_t sizeOfReadData) {
if (stringCompare(readData, "ABC") {
... Do stuff here...
state = STATE_1;
} else {
... Do stuff here...
state = STATE_3;
}}},
{STATE3, 30, 4, { (uint8_t* readData, uint16_t sizeOfReadData) {
if (stringCompare(readData, "ABCD") {
... Do stuff here...
state = STATE_3;
} else {
... Do stuff here...
state = STATE_2;
}}},
};Do I need to write my own pre-compile code interpreter/generator script that would place the anonymous code in functions outside the stateMachineStep_s array or is there something clever I can do (perhaps with macros or C++)?
the
readDataResultCallback
member of your structure is just a fancy pointer, either 32 or 64 bits long depending on your architecture, so it can only be initialised with the memory address of a function. So you could have something like the following...
void OnState1(uint8_t* readData, uint16_t sizeOfReadData)
{
...
}stateMachineStep_s stateMachineSteps[3] = {
{STATE1, 10, 2, &OnState1}
...
}which, to be honest, is not significantly more typing. You could also use macros to generate some of the code but that comes with it's own issues. C++11 and greater support lambda expressions which will allow you to initialise your structs with a similar syntax to your example but in that case you would have to swap your function pointer to an std::function<> type. If you don't have c++11 support the boost library offers a similar function pointer but without the nicer lambda syntax.
-
the
readDataResultCallback
member of your structure is just a fancy pointer, either 32 or 64 bits long depending on your architecture, so it can only be initialised with the memory address of a function. So you could have something like the following...
void OnState1(uint8_t* readData, uint16_t sizeOfReadData)
{
...
}stateMachineStep_s stateMachineSteps[3] = {
{STATE1, 10, 2, &OnState1}
...
}which, to be honest, is not significantly more typing. You could also use macros to generate some of the code but that comes with it's own issues. C++11 and greater support lambda expressions which will allow you to initialise your structs with a similar syntax to your example but in that case you would have to swap your function pointer to an std::function<> type. If you don't have c++11 support the boost library offers a similar function pointer but without the nicer lambda syntax.
Josh Gray2 wrote:
which, to be honest, is not significantly more typing
It's not a matter of typing less, it's a matter of having code that is easy to read (I expect to have arount 50-60 states).
Josh Gray2 wrote:
If you don't have c++11 support the boost library offers a similar function pointer but without the nicer lambda syntax.
When I googled it, it seems GCC has terrific support for C++.
Josh Gray2 wrote:
C++11 and greater support lambda expressions which will allow you to initialise your structs with a similar syntax to your example but in that case you would have to swap your function pointer to an std::function<> type.
Could someone knowledgeable in C++ please help with the syntax for the example I provided? Do I need to put it inside a C++ file or it is possible have sections of a C-file containing C++ code?
-
Josh Gray2 wrote:
which, to be honest, is not significantly more typing
It's not a matter of typing less, it's a matter of having code that is easy to read (I expect to have arount 50-60 states).
Josh Gray2 wrote:
If you don't have c++11 support the boost library offers a similar function pointer but without the nicer lambda syntax.
When I googled it, it seems GCC has terrific support for C++.
Josh Gray2 wrote:
C++11 and greater support lambda expressions which will allow you to initialise your structs with a similar syntax to your example but in that case you would have to swap your function pointer to an std::function<> type.
Could someone knowledgeable in C++ please help with the syntax for the example I provided? Do I need to put it inside a C++ file or it is possible have sections of a C-file containing C++ code?
arnold_w wrote:
Could someone knowledgeable in C++ please help with the syntax for the example I provided? Do I need to put it inside a C++ file or it is possible have sections of a C-file containing C++ code?
You can't put C++ code inside a C file, but since C++ is (mostly) a superset of C, most C code will compile without issue. About the only thing you can't do is use a C identifier that is a C++ keyword (e.g.
int new;
will not compile in C++). Depending on what you're running on your ARM, you might be able to get C# (mono) up and running on your ARM device (e.g. raspberry pi or similar).Keep Calm and Carry On
-
Josh Gray2 wrote:
which, to be honest, is not significantly more typing
It's not a matter of typing less, it's a matter of having code that is easy to read (I expect to have arount 50-60 states).
Josh Gray2 wrote:
If you don't have c++11 support the boost library offers a similar function pointer but without the nicer lambda syntax.
When I googled it, it seems GCC has terrific support for C++.
Josh Gray2 wrote:
C++11 and greater support lambda expressions which will allow you to initialise your structs with a similar syntax to your example but in that case you would have to swap your function pointer to an std::function<> type.
Could someone knowledgeable in C++ please help with the syntax for the example I provided? Do I need to put it inside a C++ file or it is possible have sections of a C-file containing C++ code?
-
Josh Gray2 wrote:
which, to be honest, is not significantly more typing
It's not a matter of typing less, it's a matter of having code that is easy to read (I expect to have arount 50-60 states).
Josh Gray2 wrote:
If you don't have c++11 support the boost library offers a similar function pointer but without the nicer lambda syntax.
When I googled it, it seems GCC has terrific support for C++.
Josh Gray2 wrote:
C++11 and greater support lambda expressions which will allow you to initialise your structs with a similar syntax to your example but in that case you would have to swap your function pointer to an std::function<> type.
Could someone knowledgeable in C++ please help with the syntax for the example I provided? Do I need to put it inside a C++ file or it is possible have sections of a C-file containing C++ code?
arnold_w wrote:
Could someone knowledgeable in C++ please help with the syntax for the example I provided? Do I need to put it inside a C++ file or it is possible have sections of a C-file containing C++ code?
#include typedef std::function readDataResultCallback_t;
typedef struct __attribute__((__packed__)) {
stateMachineState_e state;
uint32_t startAddr;
uint16_t numRegsToRead;
readDataResultCallback_t readDataResultCallback;
} stateMachineStep_s;stateMachineStep_s stateMachineSteps[3] = {
{STATE1, 10, 2, [](uint8_t* readData, uint16_t sizeOfReadData) {
if (stringCompare(readData, "AB") {
... Do stuff here...
state = STATE_2;
} else {
... Do stuff here...
state = STATE_3;
}},
... -
I am writing code for an ARM processor and compiling with GCC. I have done some C# programming and there you're allowed to declare delegates inside structures. What's the closest thing I can achieve the same thing in my ARM-project? For example, it would great if I could write a state machine like this:
typedef void (*readDataResultCallback_t)(uint8_t* readData, uint16_t sizeOfReadData);
typedef enum {
STATE1 = 0,
STATE2 = 1,
STATE3 = 2,
} stateMachineState_e;typedef struct __attribute__((__packed__)) {
stateMachineState_e state;
uint32_t startAddr;
uint16_t numRegsToRead;
readDataResultCallback_t readDataResultCallback;
} stateMachineStep_s;static stateMachineState_e state = STATE1;
stateMachineStep_s stateMachineSteps[3] = {
{STATE1, 10, 2, { (uint8_t* readData, uint16_t sizeOfReadData) {
if (stringCompare(readData, "AB") {
... Do stuff here...
state = STATE_2;
} else {
... Do stuff here...
state = STATE_3;
}}},
{STATE2, 20, 3, { (uint8_t* readData, uint16_t sizeOfReadData) {
if (stringCompare(readData, "ABC") {
... Do stuff here...
state = STATE_1;
} else {
... Do stuff here...
state = STATE_3;
}}},
{STATE3, 30, 4, { (uint8_t* readData, uint16_t sizeOfReadData) {
if (stringCompare(readData, "ABCD") {
... Do stuff here...
state = STATE_3;
} else {
... Do stuff here...
state = STATE_2;
}}},
};Do I need to write my own pre-compile code interpreter/generator script that would place the anonymous code in functions outside the stateMachineStep_s array or is there something clever I can do (perhaps with macros or C++)?
If you are allowed to use (a modern version of) the
C++
compiler (g++
), then something like this#include
#include
using namespace std;using MyCallback = function ;
struct State
{
int i;
MyCallback mc;
};State s[] =
{
{ 10, [](const char * p, size_t size ){ for (size_t n=0; n
would work. -
If you are allowed to use (a modern version of) the
C++
compiler (g++
), then something like this#include
#include
using namespace std;using MyCallback = function ;
struct State
{
int i;
MyCallback mc;
};State s[] =
{
{ 10, [](const char * p, size_t size ){ for (size_t n=0; n
would work.I converted my project to a C++ project (I could see that the line org.eclipse.cdt.core.ccnature got added inside my .project file) and added your code, but I get the following error message when I try to build the project: cannot open linker script file -Wl,-Map=output.map: No such file or directory MyProject C/C++ Problem Do you know what I'm doing wrong?
-
I converted my project to a C++ project (I could see that the line org.eclipse.cdt.core.ccnature got added inside my .project file) and added your code, but I get the following error message when I try to build the project: cannot open linker script file -Wl,-Map=output.map: No such file or directory MyProject C/C++ Problem Do you know what I'm doing wrong?
-
The option format is incorrect, it should be
-Wl,-Map,output.map
as described at Link Options (Using the GNU Compiler Collection (GCC))[^].So I went to Project Properties -> C/C++ Build -> Settings -> MCU G++ Linker and replaced the following Command line pattern:
${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}
with
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -T"" -Wl,-Map,output.map -Wl,--gc-sections -fno-exceptions -fno-rtti -o "MyProject.elf" @"objects.list" -lm
When I build the project and look inside the console window, I see the following:
Invoking: MCU G++ Linker
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -T"" -Wl,-Map,output.map -Wl,--gc-sections -fno-exceptions -fno-rtti -o "MyProject.elf" @"objects.list" -lm -lm
c:/ac6/systemworkbench/plugins/fr.ac6.mcu.externaltools.arm-none.win32_1.17.0.201812190825/tools/compiler/bin/../lib/gcc/arm-none-eabi/7.3.1/../../../../arm-none-eabi/bin/ld.exe: cannot open linker script file -Wl,-Map,output.map: No such file or directoryWhat did I do wrong?
-
So I went to Project Properties -> C/C++ Build -> Settings -> MCU G++ Linker and replaced the following Command line pattern:
${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}
with
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -T"" -Wl,-Map,output.map -Wl,--gc-sections -fno-exceptions -fno-rtti -o "MyProject.elf" @"objects.list" -lm
When I build the project and look inside the console window, I see the following:
Invoking: MCU G++ Linker
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -T"" -Wl,-Map,output.map -Wl,--gc-sections -fno-exceptions -fno-rtti -o "MyProject.elf" @"objects.list" -lm -lm
c:/ac6/systemworkbench/plugins/fr.ac6.mcu.externaltools.arm-none.win32_1.17.0.201812190825/tools/compiler/bin/../lib/gcc/arm-none-eabi/7.3.1/../../../../arm-none-eabi/bin/ld.exe: cannot open linker script file -Wl,-Map,output.map: No such file or directoryWhat did I do wrong?
arnold_w wrote:
What did I do wrong?
Nothing that I can see. I just did a build with
-Wl,-Map,output.map
and it worked fine. But the error message you have suggests that the linker is trying to read-Wl,-Map,output.map
as a script file for some reason. I am not sure whether theMCU g++ linker
is significantly different from the standardld linker
, but you may want to check the documentation. -
If you are allowed to use (a modern version of) the
C++
compiler (g++
), then something like this#include
#include
using namespace std;using MyCallback = function ;
struct State
{
int i;
MyCallback mc;
};State s[] =
{
{ 10, [](const char * p, size_t size ){ for (size_t n=0; n
would work.It's probably a stupid question, but is there any way to make anonymous function usage like that compile inside a file with .c (not .cpp) extension? I know I'm allowed to put snippets of C-code inside a C++ file, but I suppose the opposite isn't possible (not even with clever macros)?