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的吗?