1

So, say I have the following C++ header, testheader.h:

struct mystruct
{
  struct myinnerstruct
  {
        int x;
  } astruct;
};

struct myinnerstruct
{
    int x;
};

and the following C++ source, test.cpp:

#include "testheader.h"
using namespace std;
int main()
{
    return 0;
}

g++ gives no issues during compile/link.

Now, if I have the same header, but instead of the C++ source, a C source file test.c:

#include "testheader.h"
int main()
{
  return 0;
}

And I compile with gcc, I get the following error:

error: redefinition of struct myinnerstruct

So, I gather that the scope of the C version is the translation unit, and the C++ version is block scoped? Can someone confirm this is the case, and maybe give me a reason of why it makes sense? I'm doing some mixing of C and C++ code, and this is giving me quite a bit of trouble.

Any insight is greatly appreciated. Thanks!

prelic
  • 4,450
  • 4
  • 36
  • 46
  • why not just remove the redefinition? – stark May 17 '12 at 01:04
  • 1
    @stark : Because it's _not_ a redefinition (in C++), it's an entirely different type. – ildjarn May 17 '12 at 01:05
  • @stark As in rename the inner struct? In this trivial example, that is a clear solution. But the code I'm actually working with is not that simple, and I don't have that flexibility, unfortunately. – prelic May 17 '12 at 01:06
  • 1
    An even cuter one is including, from a C++ program, a C header that has something like: `typedef struct my_struct { } my_struct;` – Edward Strange May 17 '12 at 01:10
  • What I mean is just define myinnerstruct once, then use just the name inside mystruct. – stark May 17 '12 at 01:12
  • 1
    @CrazyEddie - I'm sorry, I didn't understand that. Could you rephrase or elaborate? Thanks for the help. – prelic May 17 '12 at 01:15

4 Answers4

2

In C nested structs do not actually live in their parents scope. However in C++ they do- teststruct::innerstruct is a different type to innerstruct. This is to improve encapsulation in C++ code. Without this rule, no two types in the same namespace could define a nested iterator class, for example, which would be extremely bad.

C treats structs in plenty of other very silly ways, so it's no surprise that they did the wrong thing here. However, C does not otherwise allow type scoping and having a sane rule here would have introduced many additional concepts to the language- ultimately, it would have required the introduction of namespaces, which for some reason was never done.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • Thanks for the help. So this weird (IMO) C scoping issue is limited to structures? Does that explain why I can declare a variable `x` in a C `main`, and then have `main` call `myfunc`, which also declares a variable `x`, and gcc is happy? – prelic May 17 '12 at 01:17
  • If namespaces were introduced, I believe they would have to also introduce name mangling in C, which would cause many problems. – Jesse Good May 17 '12 at 01:37
  • @Jesse: Not necessarily. It is templates and overloading that genuinely introduce name mangling problems. Namespaces alone can be trivially mangled- and have a defined mangling, which would not be problematic at all. – Puppy May 17 '12 at 06:44
2

In C, the definition of inner struct goes outside of the outer struct, which is not the case in C++.

This has been explained in this blog: Incompatibilities Between ISO C and ISO C++ among many other things in C vs. C++ with a reference to C99 and c++98 ISO standards.

P.P
  • 117,907
  • 20
  • 175
  • 238
1

There are no scopes in C, so everything is in the "global" namespace (in C++ speak)

Attila
  • 28,265
  • 3
  • 46
  • 55
  • Ok, then my next question would be, why can I declare a variable `x` in a C `main`, and then have `main` call `myfunc`, which also declares a variable `x`, and all is okay? Why is there no symbol clashing there? – prelic May 17 '12 at 01:13
  • 1
    Because we are talking about scope of types here, not of variables – Attila May 17 '12 at 01:26
0

A cleaner way which works in bot C and C++ is:

struct myinnerstruct
{
    int x;
};

struct mystruct
{
  struct myinnerstruct astruct;
};
stark
  • 12,615
  • 3
  • 33
  • 50
  • 1
    Only "works" in C++ if `::myinnerstruct` and `mystruct::myinnerstruct` are intended to be the same type. – Robᵩ May 17 '12 at 01:20
  • Thanks for the tip. The issue is that I cannot change the definition or even any of that header file at all. – prelic May 17 '12 at 01:20
  • @Robᵩ if they aren't the same type, then it doesn't work in C no matter what. If you don't have a C header, you need to write in C++ – stark May 17 '12 at 01:35