I am looking for the best know method for statically defining C/C++ data structures which need to be circularly linked. E.g. a tree where child and parent both need pointers to each other.
extern struct Op op_subops[4]; // fwd ref to children of ops
struct Op
{
const char *name;
struct Op *parent;
struct Op *children;
};
struct Op ops[128] = {
{"op",0,&op_subops[0]}
};
struct Op op_subops[4] = {
{"subop1",&ops[1],0},
{"subop2",&ops[1],0}
};
The above compiles (g++ 5.2). The extern keyword seems to permit me to create a forward reference from ops into ops_subops, and the other direction works out naturally since ops precedes ops_subops.
The thing I don't like is that, I'd prefer both arrays to be static (not create a publicly visible symbol in the object file).
I could use an integer index for one of the directions, but that seems a little hokey, and I'd rather just have the linker resolve the address for me.
Anyone have a magic keyword to make this work?
Thanks!
EDIT: I need to avoid things like C++ static constructors and bleeding-edge C++17 extensions (sadly). And my approach needs to platform independent.
As you're looking for declaring your arrays as static and can't accept them remaining global, I assume that your intention is to have both arrays remain inaccessible from the outside world.
Idea 1: just (forward-)declare the static array:
I first thought this would be the solution for the forward delclaration. This compiled well with gcc for a C file: online demo 1. But unfortunatemy it doesn't compile neither on MSVC nor on C++ because it's not standard:
In reality it's simpler: just declare the array with its dimension:
Online demo 2
The subsequent initialization doesn't define/redefine the array; it designates the already declared array to be initialized. In fact you could leave the array dimension out from the initialization. And this time it compiles on gcc and on MSVC:
Idea 2: put both arrays in an unnamed namespace (C++ only)
Then you no longer have to decare the items as static: the unnamed namespace ensures that other compilation units can't refer to these objects