0

I have the following code that produces a compile error. It is for a command parser for a STM32 micro-controller written in C++. Basically I have a CMD_DEF_ST struct with a string and a function pointer to handle that string. I added a further pointer to another CMD_DEF_ST array in the struct, to be able to handle command parameters. I cannot get the initialisation right unfortunately. I do not want to initialize it at runtime, as it all has to go into const FLASH memory.

#include <stdio.h>

// **************************
// define command structure
// **************************

// struct forward declaration
typedef struct cmd_def_st CMD_DEF_ST;                       

// typedef for command handler function
typedef void (*CMD_FUNC_HANDLER)(const CMD_DEF_ST* cmddef); 

struct cmd_def_st
{
    const char* cmdstr;          // command string
    const CMD_FUNC_HANDLER func; // pointer to handler
    const CMD_DEF_ST* params;    // pointer to sub parameters
};




// **************************
// declare some commands
// **************************
const CMD_DEF_ST cmd = {"swrst" , [] (const CMD_DEF_ST* cmd) { printf("swrst\n"); },
    NULL};

// **************************
// produces:
// error: braces around scalar initializer for type 'const CMD_DEF_ST* 
//                {aka const cmd_def_st*}'
// **************************
const CMD_DEF_ST cmd2 = { "echo" , [] (const CMD_DEF_ST* cmd) { printf("Error\n"); },
    {
        {"on" , [] (const CMD_DEF_ST* cmd) { printf("Echo on\n"); }, NULL },
        {"off" , [] (const CMD_DEF_ST* cmd) { printf("Echo off\n"); }, NULL },
        NULL
    }
    };

int main()
{
    cmd.func(&cmd); // prints "swrst"

    return 0;
}

I had a look here gcc warning: braces around scalar initializer and here initializing array of pointers to structs. It gave me a few ideas to try, but I could not quite figure out how to make it work for my own code.

I tried changing the struct definition to:

struct cmd_def_st
{
    const char* cmdstr;          // command string
    const CMD_FUNC_HANDLER func; // pointer to handler
    const CMD_DEF_ST** params;    // pointer to sub parameters
};

with

// **************************
// produces:
// error: taking address of temporary [-fpermissive]|
// error: taking address of temporary [-fpermissive]|
// error: taking address of temporary array|
// **************************
const CMD_DEF_ST cmd2 = { "echo" , [] (const CMD_DEF_ST* cmd) { printf("Error\n"); },
    (const CMD_DEF_ST* []){
        &(const CMD_DEF_ST){"on" , [] (const CMD_DEF_ST* cmd) { printf("Echo on\n"); }, NULL },
        &(const CMD_DEF_ST){"off" , [] (const CMD_DEF_ST* cmd) { printf("Echo off\n"); }, NULL },
        NULL
    }
    };

but I still got a compile error.

Can someone tell me what is the correct way to initialize cmd2, or does someone know of a good way to do this?

Armand Jordaan
  • 348
  • 2
  • 11

2 Answers2

1

I don't know if it can be done in the way you are trying, but splitting the initialization in two works. First the array of sub-commands followed by the command and just passing in the pointer.

const CMD_DEF_ST subcmd1[] = {{"on" , [] (const CMD_DEF_ST* cmd) { printf("Echo on\n"); }, NULL }, {"off" , [] (const CMD_DEF_ST* cmd) { printf("Echo off\n"); }, NULL }};
const CMD_DEF_ST cmd2 = { "echo" , [] (const CMD_DEF_ST* cmd) { printf("Error\n"); }, subcmd1};
super
  • 12,335
  • 2
  • 19
  • 29
1

if in the cmd_def_st struct you use const CMD_DEF_ST* params; you are trying to initialize a scalar type (pointer) with array of structs. So here you actually need an address of CMD_DEF_ST type (like it is suggested in the super's answer).

In your second case you are trying to take an address of rvalue, a temporary object that will cease to exist after the current statement, so you are receiving an error.

if you are not happy with that two-step initialization I might suggest making structs both for cmds and subcmds to provide type completeness for the params array in the cmd_def_st:

struct subcmd_def_st
{
    const char* cmdstr;          // command string
    const CMD_FUNC_HANDLER func; // pointer to handler
//    const SUBCMD_DEF_ST params;     // assuming no sub-subcmds
};

struct cmd_def_st
{
    const char* cmdstr;          // command string
    const CMD_FUNC_HANDLER func; // pointer to handler
    const subcmd_def_st params[];     // pointer to sub parameters
};

const CMD_DEF_ST cmd2 =
    { 
        "echo" , 
        [] (const CMD_DEF_ST* cmd) { printf("Error\n"); },
        {
            { "on" , [] (const CMD_DEF_ST* cmd) { printf("Echo on\n"); } },
            { "off" , [] (const CMD_DEF_ST* cmd) { printf("Echo off\n"); } },
            { NULL }
        }
    };
xdimy
  • 46
  • 6
  • Thanks, I tried this but then I run into this https://stackoverflow.com/questions/21152171/too-many-initializers-for-int-0-c problem, – Armand Jordaan Oct 19 '19 at 22:17
  • I tried to compile this code on g++ 5 and really that initialization problem appeared, but after upgrade to g++ 7 it was compiled with no errors (also with std=c++11 option) – xdimy Oct 20 '19 at 10:00
  • Thank you. I was on GCC 5. So as you correctly say building this with GCC 7 does exactly what I wanted. Thank you very much. I have changed to this as the accepted solution. – Armand Jordaan Oct 22 '19 at 05:38