2

I think it's a simple question, but I can't get the answer by myself. I have a struct like this and want to initialize an array of commands.

typedef struct LPWA_COMMAND
{
    LPWA_COMMAND_TYPE type;
    const char text[];

}LPWA_COMMAND;

LPWA_COMMAND_TYPE is just a simple enum. Don't mind that.

I don't want to give text a fixed size like: const char text[30], since I know every command before compiling the program and it would be a waste of memory.

Since it is possible to do that: const char text[] = "Hi"; there has to be a solution similar to this.

This works:

LPWA_COMMAND test = {
        LPWA_EXTRA, "ATI"
};

but this is giving me an error: (initialization of flexible array member in a nested context)

LPWA_COMMAND test2[1] = {
        {LPWA_EXTRA, "ATI"}
};

BTW: LPWA_COMMAND has to be a typedef.

Thanks!

Terror404
  • 51
  • 6
  • 2
    You will most likely need to dynamically allocate the object (via `malloc()`). You can write `LWPA_COMMAND*cmd=malloc(offsetof(LWPA_COMMAND, text)+TEXTLENGTH);` where `TEXTLENGTH` is whatever you want it to be, including runtime computed (remember to allocate space for null-termination though). – EOF Apr 06 '20 at 13:00
  • 4
    The Problem is that you want to create an array with elements of different size, which doesn't work. However, if all you need are strings, then just don't use a flexible array member, but instead define text as char*. Then you can initialize it just fine with constant strings, they'll just be stored elsewhere – Felix G Apr 06 '20 at 13:03
  • I always want to avoid malloc, realloc or calloc, because there are so many mistakes that can be made using pointers this way. Finding them is a real struggle for me. – Terror404 Apr 06 '20 at 13:04
  • @FelixG Yes, I also thought about that solution, but I was hoping that there's another way xD – Terror404 Apr 06 '20 at 13:06
  • @Terror404 None that i know of that doesn't use dynamic allocation. Do you really need the strings to be stored in-place? – Felix G Apr 06 '20 at 13:08
  • I once asked a [question](https://stackoverflow.com/q/30138626/3185968) about allocating (effectively) a structure with a flexible array member without `malloc()`. It's possible, but it's just barely well-defined behavior. – EOF Apr 06 '20 at 13:08
  • @FelixG: you will either store the data directly inside the struct (in which case you need to know the size in advance), or the struct will only contain the pointer to another place in memory. – vgru Apr 06 '20 at 13:10
  • @FelixG No, not really. If there's no solution storing them like this in a struct, I will end up just creating an array of strings. – Terror404 Apr 06 '20 at 13:12
  • Just to make it clear: I know every size of everything in advance – Terror404 Apr 06 '20 at 13:13
  • 3
    Just don't use flexible arrays, they rarely useful, and this is one of those cases. `sizeof(LPWA_COMMAND)` is still the same as if you used a plain pointer. [Just use a plain pointer](https://godbolt.org/z/TL6FYi). – vgru Apr 06 '20 at 13:14
  • @Groo That's a clear way, thank you! – Terror404 Apr 06 '20 at 13:27
  • 1
    Replace `const char text[];` with `const char *text;` and you're done. – Jabberwocky Apr 06 '20 at 13:35

1 Answers1

0

Thanks to FelixG, Groo and Jabberwocky for your advices.

I've now solved my issue like this:

typedef struct LPWA_COMMAND
{
    LPWA_COMMAND_TYPE type;
    const char *text;

} LPWA_COMMAND;

typedef enum LPWA_COMMAND_ID
{
    ATI = 0,
    QPING,
    QPOWD,
    // ... more commands ...
    NUMBEROFCOMMANDS
} LPWA_COMMAND_ID;

LPWA_COMMAND commandset[NUMBEROFCOMMANDS]= {
         [ATI].text = "ATI", [ATI].type = LPWA_EXTRA ,
         [QPING].text = "QPING", [QPING].type = LPWA_NORMAL ,
         [QPOWD].text = "QPOWD", [QPOWD].type = LPWA_NORMAL
         // ... more commands ...
};

It's also possible to do the initialization in a seperate function, like Groo suggested:

LPWA_COMMAND create_command(const char * text, LPWA_COMMAND_TYPE type )
{
    return (LPWA_COMMAND){ .text = text , .type = type};
}
Terror404
  • 51
  • 6
  • No -- this didn't solve your problem, it may allow it to compile, but if you have a FAM, the struct can NOT be used as an array. [C11 Standard - 6.7.2.1 Structure and union specifiers(p3)](http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p3) See also [How does an array of structures with flexible array members behave?](https://stackoverflow.com/questions/36118536/how-does-an-array-of-structures-with-flexible-array-members-behave) – David C. Rankin Apr 07 '20 at 05:21
  • It's not a FAM anymore, it's a pointer now. So the size of LPWA_COMMAND is constant. The text itself is stored somewhere else. I think I can use it as an array, but I've not tested it yet. – Terror404 Apr 07 '20 at 06:05
  • You are correct -- my bad, I was looking at the FAM in your question. You can create an array from a struct as long as it has no FAM. – David C. Rankin Apr 07 '20 at 06:20