Forward declaration of static instances of C structure in C ++

I am writing a code generator, well, actually a data generator that will create data structures of this form (it is obvious that the actual data structures are much more complex):

typedef struct Foo {
  int a;
  struct Foo* foo;
} Foo;

extern Foo f1;
extern Foo f2;

Foo f1 = {1, &f2};
Foo f2 = {2, &f1};

This is portable for all the C and C ++ compilers I've tried.

I would like to forward declare these instances of the structure as static, so as not to pollute the global space of variables, as in:

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

Although this works with gcc and probably all C compilers, the above code does not work with C ++ compilers and leads to a compilation error:

error: redefinition of ‘Foo f1’
error: ‘Foo f1’ previously declared

, ++. , , ++, C ?

+3
7

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 ++ f1 f2.

+7

, , :

#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

++ extern 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
+7

, , Fiasco. , , .

. . , . C, ++.

extern Foo f1;

.

static Foo f1;

f1 struct Foo.

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 */

, , .

+4

, . . , , , , .

EDIT: , , :

@dirkgently: , C : " , ".

++ .

EDIT:

. , . #ifdef __cplusplus, .

+2

. , , ++ C.

- , , - 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 ++.

+1

(.cpp .h):

code.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). .

0

. , , .

[ , , - , . ]

, , :

:

#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

And we can do:

static_forward(struct foo foo_instance)

void some_function(void)
{
  do_something_with(&foo_instance);
}

static_def(struct foo foo_instance = { 1, 2, 3 })

The C extension is simple, it looks like this:

static struct foo foo_instance;

void some_function(void)
{
  do_something_with(&foo_instance);
}

static struct foo foo_instance = { 1, 2, 3 };

The C ++ extension is as follows:

namespace { extern struct foo foo_instance; }

void some_function(void)
{
  do_something_with(&foo_instance);
}

namespace { struct foo foo_instance = { 1, 2, 3 }; }

So, in a nutshell, thanks to anonymous namespaces, C ++ actually does not have a static problem with a direct link, only the problem of its implementation with a method incompatible with C, which is a bridge with macros.

Several anonymous areas of the namespace in the same translation system are the same namespace, and the surrounding content area outside the namespace is visible.

0
source

Source: https://habr.com/ru/post/1704002/


All Articles