我正在寻找用于静态定义需要循环链接的C / C ++数据结构的最佳方法。例如。一个树,其中孩子和父母都需要彼此指针。
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}
};
以上编译(g ++ 5.2)。 extern
关键字似乎允许我创建从ops
到ops_subops
的转发引用,而另一个方向自然ops
在ops_subops
之前。{ / p>
我不喜欢的是,我更喜欢两个数组都是static
(不在目标文件中创建公开可见的符号)。
我可以为其中一个方向使用整数索引,但这看起来有点不对劲,我宁愿让链接器为我解析地址。
任何人都有一个神奇的关键字来完成这项工作吗?
谢谢!
编辑:我需要避免像C ++静态构造函数和尖端的C ++ 17扩展(遗憾的是)。我的方法需要平台独立。答案 0 :(得分:2)
在C或C ++中,底线是您在声明对象之前不能引用它,但是这两种语言都允许您编写声明名称和(可能不完整)类型的“前向声明”而不使用定义对象。我更熟悉C,我会从这个角度回答;一些语义可能在C ++中有所不同。
在C中,你提出的代码的主要问题是它与数组的要求相冲突
只要指定了数组类型,元素类型就应该完整。
(C2011,6.2.5 / 20)
这意味着虽然您可以在没有大小的情况下向前声明数组op_subops
(在这种意义上保留其类型不完整),但在定义类型struct Op
之前,您不能为它发出任何声明。这可以通过交换两个声明的位置来解决。
纠正了排序问题后,在C中声明两个数组都有static
链接完全没问题;你必须确保如果任何对象被多次声明(即op_subops
),所有声明都同意它的链接:
struct Op
{
const char *name;
struct Op *parent;
struct Op *children;
};
static struct Op op_subops[4]; // fwd ref to children of ops
static struct Op ops[128] = {
{"op",0,&op_subops[0]}
};
static struct Op op_subops[4] = {
{"subop1",&ops[0],0},
{"subop2",&ops[1],0}
};
如果您愿意,可以从第一个声明中省略op_subop
的长度,事实上我建议您这样做,以避免在两个声明中保持长度一致。
虽然你要求“最好的[已知]方法”,但这可能是一个意见问题,因为背景有色,而且意见问题在这里是偏离主题的。另一方面,在这种情况下,你似乎需要为孩子们安排一个数组,所以在没有改变类型的情况下,我看不出有什么其他选择。
答案 1 :(得分:1)
当您正在寻找将数组声明为静态并且无法接受它们保持全局时,我认为您的意图是让两个数组仍然无法从外部世界访问。
我首先想到这将是前向宣言的解决方案。使用gcc编译好C文件: online demo 1 。但不幸的是,它既没有在MSVC上也没有在C ++上编译,因为它不是标准的:
static struct Op op_subops[]; // compiler dependent - it's standard!
实际上它更简单:只需 声明 数组及其维度:
static struct Op op_subops[4]; // as simple as that
后续初始化不会定义/重新定义数组;它指定要初始化的已声明的数组。实际上,您可以从初始化中退出数组维度。这次它在gcc和MSVC上编译:
static struct Op op_subops[] = { // [] or [4]
...
};
然后您不再需要将项目视为静态:未命名的命名空间可确保其他编译单元无法引用这些对象