j123b567
j123b567

Reputation: 3439

Initializing constant from constant lookup table

I have a constant lookup table

static const uint32_t lut [] = {0, 20, 100, 350, 560};

I have a struct

typedef struct {
    uint32_t value;
    const char * name;
} strct_t;

And I would like to create global constant instance of that struct

const struct_t def_myname = {
    .value = lut[DEF_MYNAME_ID],
    .name = "myname",
};

but I need to define DEF_MYNAME_ID in other place, so I have this in some header file

#define DEF_MYNAME_ID 3

This can't compile, because of this error initializer element is not constant

There are multiple questions in stackoverflow asking what to do with initializer element is not constant, but none covers my needs.

Is there a way how to do this? For example by defining lut as macro? I don't need it in other place.

Is there something like

#define LUT(a) ...

usabele as const initializer?

Upvotes: 0

Views: 777

Answers (2)

Felipe Lavratti
Felipe Lavratti

Reputation: 2967

Sure, macros can do that. This is actually a safer code, if you pick an index out of range, it won't compile.

First we define our dictionary

#define _val0 0
#define _val1 20
#define _val2 100
#define _val3 350
#define _val4 560

Now we need a PRIMITIVE_CAT to force expansion of the argument of the macro LUT.

#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__

And finaly, the LUT.

#define LUT(X) PRIMITIVE_CAT(_val, X)

Now your code.

#define DEF_MYNAME_ID 3
const struct_t def_myname = {
    .value = LUT(DEF_MYNAME_ID),
    .name = "myname",
};

Upvotes: 1

shinobi
shinobi

Reputation: 361

I think you're mostly out of luck, at least with plain C, as even the following wouldn't compile as a static initializer:

int v = ((uint32_t[]) { 10, 20, 30, 40, 50 })[3];

FWIW, this would be fine:

static const uint32_t *pv = lut + DEF_MYNAME_ID;

as would be this (essentially the same):

static const uint32_t *pv = &(lut[DEF_MYNAME_ID]);

Also, in C++, your whole case would be fine as given.

Upvotes: 0

Related Questions