0

I'd like to keep my keywords in a struct:

typedef const char* label;
const struct keywords_t
{
    label init;
    label moveUnit;
} keywords;

But I'd like to be able to check whether a keyword is valid with a for loop, so I tried to initialize the struct like this:

const label allowed_keywords[] =
{
    "INIT",
    "MOVE"
};

const struct keywords_t keywords =
{
    allowed_keywords[0],
    allowed_keywords[1]
};

This gives me an

error: initializer element is not constant

What am I doing wrong? The whole array is constant, though.

6
  • Clang accepts it without complaint. What compiler are you using? I think it's not portable; see stackoverflow.com/a/3025106/4323 Commented Apr 21, 2016 at 13:55
  • 1
    @JohnZwinck clang++ accept it, but not clang. Commented Apr 21, 2016 at 14:00
  • Don't typedef pointers! Commented Apr 21, 2016 at 14:50
  • @JohnZwinck: This will not work for C, but maybe for C++. C does not have symbolic constants other than enum constants. Commented Apr 21, 2016 at 14:52
  • @Olaf why? (15 chars) Commented Apr 21, 2016 at 19:11

2 Answers 2

7

In C constvariables are not constants, they are simply variables that cannot be changed. Thus their value cannot be used in constant expressions, like in struct initializer.

One work-around could be to use preprocessor defines for initializers:

#define KEYWORD_INIT   "INIT"
#define KEYWORD_MOVE   "MOVE"

const label allowed_keywords[] =
{
    KEYWORD_INIT,
    KEYWORD_MOVE
};

const struct keywords_t keywords = 
{
    KEYWORD_INIT,
    KEYWORD_MOVE
};

Other approach could be to use combination of enumeration and array:

typedef enum {
    KEYWORD_INIT,
    KEYWORD_MOVE
} label;

const char * const keyword_strings[] = {
    "INIT",
    "MOVE"
};

const struct keywords_t keywords =
{
    KEYWORD_INIT,
    KEYWORD_MOVE
};

// Getting keyword string would be like this:
// keyword_strings[keywords.moveUnit]
Sign up to request clarification or add additional context in comments.

1 Comment

"cannot be changed" -> "must not be changed". The const-ness is not necessarily enforced by the compiler, but guaranteed by the programmer.
1

I might be the best resource for this, but both Arrays and Structs are simple memory mapping tools.

An array of char * and a struct containing the same number of char * should have the same memory structure and the same memory footprint.

So, in practice, all you need is to cast the array into the struct rather then anything else (this will also save you memory, although this is probably not so important).

i.e.

const label allowed_keywords[] =
{
    "INIT",
    "MOVE"
};

typedef const char* label;
const struct keywords_t
{
    label init;
    label moveUnit;
};

// struct keywords_t * keywords = (struct keywords_t *) allowed_keywords;

#define keywords ((struct keywords_t *) allowed_keywords)

A few things:

  1. this needs to be tested.

  2. I would avoid using the _t for the struct keywords_t, as _t is reserved for POSIX types. I use _s for structs and _pt for pointers... but that's up to you.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.