C++ 在C++;
我正在编写一个代码生成器,实际上是一个数据生成器,它将生成这种形式的数据结构(显然,实际的数据结构要复杂得多):C++ 在C++;,c++,c,C++,C,我正在编写一个代码生成器,实际上是一个数据生成器,它将生成这种形式的数据结构(显然,实际的数据结构要复杂得多): 这是我尝试过的所有C和C++编译器的可移植性。p> 我想将这些结构实例声明为静态,以免污染全局变量空间,如: typedef struct Foo { int a; struct Foo* foo; } Foo; static Foo f1; static Foo f2; static Foo f1 = {1, &f2}; static Foo f2 = {2,
这是我尝试过的所有C和C++编译器的可移植性。p> 我想将这些结构实例声明为静态,以免污染全局变量空间,如:
typedef struct Foo {
int a;
struct Foo* foo;
} Foo;
static Foo f1;
static Foo f2;
static Foo f1 = {1, &f2};
static Foo f2 = {2, &f1};
虽然这与GCC和所有C编译器都有作用,但上面的代码与C++编译器不兼容,导致编译错误:
error: redefinition of ‘Foo f1’
error: ‘Foo f1’ previously declared
我理解为什么C++会发生这种情况。是否有一个简单的解决方案,不涉及在运行时使用代码来实现对所有C++编译器都是相同的效果,而不必使用C编译器编译某些文件? < p>您所试图避免的被称为。您可以使用函数,也可以使用默认值初始化各个对象,然后重新放置成员指针 您的代码示例的含义完全不同。你将不得不重新阅读。第一个成功是因为您有一个对象的定义和另一个对象的声明。这将同时使用C和C++。
extern Foo f1;
这是一项声明和一项初步定义
static Foo f1;
这是struct Foo
类型的对象f1
的声明和定义
static Foo f2;
同上
static Foo f1 = {1, &f2};
这是一种重新定义。您违反了以下规则,即在翻译单元中必须有一个符号定义。除此之外,您可以有多个定义,但当然,每个这样的事件必须具有相同的语法和语义
static Foo f2 = {2, &f1};
同上
extern Foo fn;
/* some code */
extern Foo fn;
/* some more ... */
Foo fn; /* finally a definition */
这很好,因为可以有多个暂定声明。不能转发声明对象,只能转发类型。外部解决方案是正确的解决方案。或者,如果您确实需要避免全局名称空间污染,请将它们设置为静态,并使用您首先调用的函数初始化它们 编辑:迈克尔·伯尔在评论中提到了原因,我想我应该把它添加到一篇帖子中: @直接:它是有效的C,因为 C标准说:“一年之内 翻译单位,每次声明 具有内部链接的标识符 表示相同的对象或功能” C++没有这样的规则 编辑:
如另一篇文章所述。您还可以使用匿名命名空间来限制变量的范围。只需在<代码>中引用命名空间的东西,就可以很好地去。 < P>这应该用C或C++编译,并给你相同的名字来访问两个编译器中的同一个东西。
#ifdef __cplusplus
namespace // use anonymous namespace to avoid poluting namespace.
{
struct StaticFoos
{
static Foo f1;
static Foo f2;
};
Foo StaticFoos::f1 = {1, &StaticFoos::f2};
Foo StaticFoos::f2 = {2, &StaticFoos::f1};
}
static const &Foo f1 = StaticFoos::f1;
static const &Foo f2 = StaticFoos::f2;
#else
static Foo f1 = {1, &f2_};
static Foo f2 = {1, &f1_};
#endif
现在在C和C++中,你可以访问<代码> F1 < /C>和<代码> F2 < /代码>。 我将创建两个文件(.cpp和.h):
代码h:typedef struct Foo {
Foo() {}
Foo(int aa, struct Foo* ff) : a(aa), foo(ff) {}
int a;
struct Foo* foo;
} Foo;
static Foo f1;
static Foo f2;
code.cpp:
void myfun()
{
f1 = Foo(1, &f2);
f2 = Foo(2, &f1);
}
我也更喜欢把所有变量,比如f1,f2。。。放入某种类型的“存储”对象(属于我自己的类或某些STL容器)。然后,我将此对象定义为静态对象。这似乎与Josh的回答具有类似的效果,但复杂性较低:
#ifdef __cplusplus
namespace {
extern Foo f1;
extern Foo f2;
Foo f1 = {1, &f2};
Foo f2 = {2, &f1};
}
#else
static Foo f1;
static Foo f2;
Foo f1 = {1, &f2};
Foo f2 = {2, &f1};
#endif
C++编译时,F1和F2的外部定义在外部可链接符号的对象文件中被公开;但是,由于它们位于匿名名称空间内,因此符号会被损坏,不会与来自另一个翻译单元的符号冲突
使用宏魔术,你可以设置一些东西,这样只有一个地方可以声明和定义f1和f2,但是如果这是机械地生成的,那么可能没有太多理由这样做 比如:#ifdef __cplusplus
#define START_PRIVATES namespace {
#define END_PRIVATES }
#define PRIVATE extern
#else
#define START_PRIVATES
#define END_PRIVATES
#define PRIVATE static
#endif
START_PRIVATES
PRIVATE Foo f1;
PRIVATE Foo f2;
Foo f1 = {1, &f2};
Foo f2 = {2, &f1};
END_PRIVATES
我遇到了这个问题。限制是令人沮丧的,我看不出为什么C++与C.</P>有这种不相容的不相容性。 我的解决方案是使用静态函数—您可以向前声明—只返回f1和f2:
typedef struct Foo {
int a;
struct Foo* foo;
} Foo;
static Foo* link_f1();
static Foo* link_f2();
static Foo f1 = {1, link_f2()};
static Foo f2 = {2, link_f1()};
static Foo* link_f1() { return &f1; }
static Foo* link_f2() { return &f2; }
遗憾的是,这不是有效的C,所以你仍然需要C和C++的不同代码。 < P>这是我在我的项目中所做的。我没有使用匿名名称空间来解决这个问题,而是使用了命名名称空间
extern Foo f1;
[多亏了Matt McNabb的有益评论,结果证明匿名名称空间可以实现超级整洁的解决方案,减少宏数量,不会产生外部名称污染。]
这允许我有两个独立的程序文本区域,中间有常规的文件范围,以获得一个整洁的解决方案:
一切都隐藏在这些宏后面:
#ifdef __cplusplus
#define static_forward(decl) namespace { extern decl; }
#define static_def(def) namespace { def; }
#else
#define static_forward(decl) static decl;
#define static_def(def) static def;
#endif
因此,我们可以:
static_forward(struct foo foo_instance)
void some_function(void)
{
do_something_with(&foo_instance);
}
static_def(struct foo foo_instance = { 1, 2, 3 })
C扩展非常简单,如下所示:
static struct foo foo_instance;
void some_function(void)
{
do_something_with(&foo_instance);
}
static struct foo foo_instance = { 1, 2, 3 };
namespace { extern struct foo foo_instance; }
void some_function(void)
{
do_something_with(&foo_instance);
}
namespace { struct foo foo_instance = { 1, 2, 3 }; }
<> C++的扩展看起来是这样的:
static struct foo foo_instance;
void some_function(void)
{
do_something_with(&foo_instance);
}
static struct foo foo_instance = { 1, 2, 3 };
namespace { extern struct foo foo_instance; }
void some_function(void)
{
do_something_with(&foo_instance);
}
namespace { struct foo foo_instance = { 1, 2, 3 }; }
< > >简单地说,由于匿名命名空间,C++实际上没有静态的前向引用问题,只是用C不兼容的方式来实现它,这是用宏来桥接的。>/P>
同一翻译单元中的多个匿名名称空间区域是同一名称空间,名称空间外的周围文件范围可以看到它。也许我只是在强调,但你想实现什么?您没有向前声明任何内容,而是创建Foo类型的变量,多次使用相同的名称。但我不知道为什么。为什么不只声明一次每个变量呢?不能声明一次变量,因为它们是交叉引用的:static Foo f1={1,&f2};静态Foo f2={2,&f1};-你必须转寄声明。是的,那是在原来的帖子里说的。问题是如何在C++中使用静态结构实例来实现与C++相同的效果。这是一种语言监督。@ DrkAtvult:它是有效的C++,因为C标准说:“在一个翻译单元中,每个具有内部链接的标识符声明表示相同的对象或函数”。C++不是设计成A的吗?