Click here to Skip to main content
15,894,180 members
Please Sign up or sign in to vote.
2.00/5 (2 votes)
See more:
I'm working on a game engine written in C with C++ bindings and have run into slight snag with ambiguity. Here's a simplified version of the problematic part of my header:


C++
/* C Code """""""""""""""""""""""""""""""""""""""""" */
extern "C"
{

struct Engine_Module
  {
    char *name;
  };

typedef struct Module Module;


extern int Engine_Module_Begin(Engine_Module *this);



}
/* CPP Code """""""""""""""""""""""""""""""""""""""""" */
namespace Engine
{
class Module
  {
    char *name;


    public: int Begin();
  }:
}


When the user is writing the game in C, the main source would be

C++
struct Application
  {
    Engine_Module base;
  };

typedef struct Application Application;


int Application_Begin(Application *this)
  {
    printf("Hello World\n");
  }


int main(int argc, char *argv[])
  {
    Application application;
    return Application_Begin(&application);
  }


When the user is writing the game in C++, the main source would be

C++
class Application : public Engine::Module
  {
    public: int Begin()
      {
        printf("Hello World\n");
      }
  };


int main(int argc, char *argv[])
  {
    Application application;
    return application.Begin();
  };



Both work fine when compiled with their respective file types, but if I attempt to use the Engine_Module struct from C++ I get an ambiguity error saying there are 2 definitions for the Engine_Module struct. I'm assuming this is because GCC's C++ classes derive from structs in some way. It's not a major issue (if anything, it even helps to enforce users of the engine I'm writing to only use C in C files and C++ in C++ files), but I'm wondering if there is a alternative to this aside from branching to a C function.

Any ideas?
Posted
Comments
Sergey Alexandrovich Kryukov 20-Nov-13 11:42am    
Certainly not. Classes and structs are essentially the same in C++. Deriving a class from some struct could not possibly create ambiguity, they would remain different types. The real problem is that Engine_Module name is really used as a type name in two different type declarations. Please find it out. The information you provided is not enough.
—SA
Ghosuwa Wogomon 20-Nov-13 12:16pm    
I didn't say that the the Engine::Module class derived from Engine_Module, I was saying that GCC seems to be creating a second Engine_Module struct definition for the Engine::Module class that throws an ambiguity error if I try to use struct Engine_Module in C++ code. If you try to initialize the application module with the C code and compile with g++, it states there are 3 instances called

typedef Engine_Module
Engine_Module
Engine_Module

Creating an instance like "struct Engine_Module module;" should fix the problem, but it doesn't. So I can only assume that both definitions are structs.
Sergey Alexandrovich Kryukov 20-Nov-13 12:23pm    
I also did not say that. No, GCC does not create anything without your code, no second definitions. I tell you, check up all your code...
—SA
Ghosuwa Wogomon 20-Nov-13 12:30pm    
Why do you assume I haven't? There is only 1 definition of the Engine_Module struct and it's typedef in my code. When compiled as C code there are no problems whatsoever. When compiled as C++ code, there an additional definition. The only thing defined in the C++ code is the Engine namespace and the Module class.

Since using "struct Engine_Module" specifically does not solve the issue, then both definitions are structs, which means GCC is creating a second Engine_Module struct under the table without my code.
Sergey Alexandrovich Kryukov 20-Nov-13 13:21pm    
Only because you blame GCC in something it cannot do...
—SA

1 solution

typedef struct Module Module;
typedef struct Application Application;

That's complete nonsense (and may in fact lead to warnings or errors). C++ (and AFAIK ANSI C as well) already let you use the struct name without having to precede it with the struct qualifier!

On a sidenote: using a self-defined type name that is identical to the name of a previously defined type is at the very least confusing, and AFAIK an error, too: whenever the conpiler finds the name Application it won't know whether you mean your typedef'd name or the struct by that name! You can define two variables of the same name within the same scope legally (to the effect that the variable defined last will hide access to the first), but you can not define types of the same name. This may in fact be the cause of your problem.

extern int Engine_Module_Begin(Engine_Module *this);

Another piece of nonsense: this has no meaning in C, but may lead to confusion for those who know C++. In fact, if you try to compile that in C++ your compiler will likely complain, because this is a reserved keyword!

As for your problem, the code you've shown doesn't even use Engine_Module (it uses Engine::Module instead), so the problem must be in other parts of your code.

More generally, I advise you to drop the dual C++/C program structure idea. If you want to make your engine accessible to both C and C++ programmers then you should just write it in C++ and then - when it's done - provide C function wrappers that hide the C++-specific interface. You're needlessly hamstringing your development by always trying to fit your API to both at once, and that simply will not work!


P.S.:
After checking the references I've found that structs in ANSI C still require the struct keyword to be used, so some sort of typedef is still necessary. However, in C++ it is not necessary, and reusing the struct name as typedef name may in fact be the casue of errors. So if the same code is compiled for both C and C++ you need to make sure those typedefs are excluded for C++ compilation!
 
Share this answer
 
v3
Comments
CPallini 22-Nov-13 4:02am    
5.In C you have to use the typedef.
Sergey Alexandrovich Kryukov 23-Nov-13 17:46pm    
Please see OP's response (not in an appropriate form, but nevertheless): http://www.codeproject.com/Questions/686779/Why-can-I-not-reject-a-solution.
—SA
Stefan_Lang 25-Nov-13 5:41am    
Thanks for the hint. The link doesn't work but I found it anyway.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900