Home > OS >  Generate nested constant structs in C at compile time
Generate nested constant structs in C at compile time

Time:05-11

I'm trying to generate a large constant lookup table at compile time in C (C99), and each entry to the lookup table has a pointer to another const program struct . this isn't possible because undeclared here can't be completion

how two edit this code to can be compilation is run ?

typedef struct  menueItem_t {
    const struct menueItem_t *menuNext;
    const struct menueItem_t *menuParent;
    const struct menueItem_t *menuChild;
    const struct menueItem_t *menuPre;
    const pFuncPara_t menuCallback;
    const char *menuLable;
} menueItem_t;


//the declaration 
const menueItem_t Settings  = {&Test, &NullItem, &NullItem, &NullItem, menuDummy, "S"};
const menueItem_t Exit  = {&NullItem, &Test, &NullItem, &NullItem, menuExit, "E"};
const menueItem_t Test  = {&Exit, &Settings, &NullItem, &Test1, menuDummy, "T"};


const menueItem_t Test1  = {&Test2, &NullItem, &Test, &NullItem, menuDummy, "T1"};
const menueItem_t Test2  = {&Test3, &Test1, &Test, &NullItem, menuDummy, "T2"};
const menueItem_t Test3  = {&NullItem, &Test2, &Test, &NullItem, menuDummy, "T3"}; 
const menueItem_t  NullItem  = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};

the error view enter image description here

CodePudding user response:

Adding forward declarations for the items you declare should fix the problem:

//forward declaration 
extern const menueItem_t Settings;
extern const menueItem_t Exit;
extern const menueItem_t Test;
 
extern const menueItem_t Test1;
extern const menueItem_t Test2;
extern const menueItem_t Test3; 
extern const menueItem_t  NullItem;

// the declaration
...

In situations when no circular references exist you can re-order the declarations to eliminate forward reference. For example, moving NullItem to the top of the declaration list would let your code compile without forward-declaring NullItem.

CodePudding user response:

As @Ian Abbott remarks either forward definition with extern or tentative definition (dropping the extern) works, see the code below. There was a NULL too many in the NullItem's initialization, a struct definition was missing and the function pointer for the callback function needed some care.

#include <stdio.h>

typedef struct pFuncPara_t {
    int status;
    char* pDescription;
} pFuncPara_t;

typedef struct  menueItem_t {
    const struct menueItem_t *menuNext;
    const struct menueItem_t *menuParent;
    const struct menueItem_t *menuChild;
    const struct menueItem_t *menuPrevious;
    const pFuncPara_t (*menuCallback)(pFuncPara_t in);
    const char *menuLabel;
} menueItem_t;


const pFuncPara_t menuDummy(pFuncPara_t in){ return in; }
const pFuncPara_t menuExit(pFuncPara_t in) { return in; }

extern const menueItem_t  NullItem;
extern const menueItem_t Test1;
extern const menueItem_t Test2;
extern const menueItem_t Test3;
extern const menueItem_t Settings;
extern const menueItem_t Exit;
extern const menueItem_t Test;

//the declaration 
const menueItem_t Settings  = {&Test, &NullItem, &NullItem, &NullItem, menuDummy, "S"};
const menueItem_t Exit  = {&NullItem, &Test, &NullItem, &NullItem, menuExit, "E"};
const menueItem_t Test  = {&Exit, &Settings, &NullItem, &Test1, menuDummy, "T"};


const menueItem_t Test1  = {&Test2, &NullItem, &Test, &NullItem, menuDummy, "T1"};
const menueItem_t Test2  = {&Test3, &Test1, &Test, &NullItem, menuDummy, "T2"};
const menueItem_t Test3  = {&NullItem, &Test2, &Test, &NullItem, menuDummy, "T3"}; 
const menueItem_t  NullItem  = {NULL,NULL,NULL,NULL,NULL,NULL};


int main(int argc, char** argv) {
    return 0;
}

CodePudding user response:

Declaring the variables as extern before you reference them will work in this case:

// forward declarations
extern const menueItem_t Settings;
extern const menueItem_t Exit;
extern const menueItem_t Test;
extern const menueItem_t Test1;
extern const menueItem_t Test2;
extern const menueItem_t Test3;
extern const menueItem_t NullItem;

//the declaration 
const menueItem_t Settings  = {&Test, &NullItem, &NullItem, &NullItem, menuDummy, "S"};
const menueItem_t Exit  = {&NullItem, &Test, &NullItem, &NullItem, menuExit, "E"};
const menueItem_t Test  = {&Exit, &Settings, &NullItem, &Test1, menuDummy, "T"};
const menueItem_t Test1  = {&Test2, &NullItem, &Test, &NullItem, menuDummy, "T1"};
const menueItem_t Test2  = {&Test3, &Test1, &Test, &NullItem, menuDummy, "T2"};
const menueItem_t Test3  = {&NullItem, &Test2, &Test, &NullItem, menuDummy, "T3"}; 
const menueItem_t NullItem  = {NULL,NULL,NULL,NULL,NULL,NULL};

That will not work if the full definitions of the variables are static:

// forward declarations
extern const menueItem_t Settings;
extern const menueItem_t Exit;
extern const menueItem_t Test;
extern const menueItem_t Test1;
extern const menueItem_t Test2;
extern const menueItem_t Test3;
extern const menueItem_t NullItem;

//the declaration 
static const menueItem_t Settings  = {&Test, &NullItem, &NullItem, &NullItem, menuDummy, "S"};
static const menueItem_t Exit  = {&NullItem, &Test, &NullItem, &NullItem, menuExit, "E"};
static const menueItem_t Test  = {&Exit, &Settings, &NullItem, &Test1, menuDummy, "T"};
static const menueItem_t Test1  = {&Test2, &NullItem, &Test, &NullItem, menuDummy, "T1"};
static const menueItem_t Test2  = {&Test3, &Test1, &Test, &NullItem, menuDummy, "T2"};
static const menueItem_t Test3  = {&NullItem, &Test2, &Test, &NullItem, menuDummy, "T3"}; 
static const menueItem_t NullItem  = {NULL,NULL,NULL,NULL,NULL,NULL};

The above code will result in errors about static declarations following non-static declarations.

An alternative to declaring the variables as extern in the forward declarations is to declare them as "tentative" definitions by omitting their initializer:

// forward declarations
const menueItem_t Settings;
const menueItem_t Exit;
const menueItem_t Test;
const menueItem_t Test1;
const menueItem_t Test2;
const menueItem_t Test3;
const menueItem_t NullItem;

//the declaration 
const menueItem_t Settings  = {&Test, &NullItem, &NullItem, &NullItem, menuDummy, "S"};
const menueItem_t Exit  = {&NullItem, &Test, &NullItem, &NullItem, menuExit, "E"};
const menueItem_t Test  = {&Exit, &Settings, &NullItem, &Test1, menuDummy, "T"};
const menueItem_t Test1  = {&Test2, &NullItem, &Test, &NullItem, menuDummy, "T1"};
const menueItem_t Test2  = {&Test3, &Test1, &Test, &NullItem, menuDummy, "T2"};
const menueItem_t Test3  = {&NullItem, &Test2, &Test, &NullItem, menuDummy, "T3"}; 
const menueItem_t NullItem  = {NULL,NULL,NULL,NULL,NULL,NULL};

That has the advantage that it can be made to work when the full definitions of the variables are static by also making the forward declarations static:

// forward declarations
static const menueItem_t Settings;
static const menueItem_t Exit;
static const menueItem_t Test;
static const menueItem_t Test1;
static const menueItem_t Test2;
static const menueItem_t Test3;
static const menueItem_t NullItem;

//the declaration 
static const menueItem_t Settings  = {&Test, &NullItem, &NullItem, &NullItem, menuDummy, "S"};
static const menueItem_t Exit  = {&NullItem, &Test, &NullItem, &NullItem, menuExit, "E"};
static const menueItem_t Test  = {&Exit, &Settings, &NullItem, &Test1, menuDummy, "T"};
static const menueItem_t Test1  = {&Test2, &NullItem, &Test, &NullItem, menuDummy, "T1"};
static const menueItem_t Test2  = {&Test3, &Test1, &Test, &NullItem, menuDummy, "T2"};
static const menueItem_t Test3  = {&NullItem, &Test2, &Test, &NullItem, menuDummy, "T3"}; 
static const menueItem_t NullItem  = {NULL,NULL,NULL,NULL,NULL,NULL};

Since the initialization of NullItem does not refer to any other menu items, it does not really need a forward declaration. Moving its full declaration before the other variables would suffice:

// forward declarations
const menueItem_t Settings;
const menueItem_t Exit;
const menueItem_t Test;
const menueItem_t Test1;
const menueItem_t Test2;
const menueItem_t Test3;

//the declaration 
const menueItem_t NullItem  = {NULL,NULL,NULL,NULL,NULL,NULL};
const menueItem_t Settings  = {&Test, &NullItem, &NullItem, &NullItem, menuDummy, "S"};
const menueItem_t Exit  = {&NullItem, &Test, &NullItem, &NullItem, menuExit, "E"};
const menueItem_t Test  = {&Exit, &Settings, &NullItem, &Test1, menuDummy, "T"};
const menueItem_t Test1  = {&Test2, &NullItem, &Test, &NullItem, menuDummy, "T1"};
const menueItem_t Test2  = {&Test3, &Test1, &Test, &NullItem, menuDummy, "T2"};
const menueItem_t Test3  = {&NullItem, &Test2, &Test, &NullItem, menuDummy, "T3"}; 
  • Related