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};
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"};