3

I have a C++ class MyClass that declare a public enum type MyEnum, and I want to use that enum in a C file. How can I do that ?

I tried to declare my functions in a C++ file and then put everything as extern "C", but sadly I am using some functions defined in big_hugly_include.h and this header does not like being included as external "C" (it gives me a template with C linkage error).

I cannot (don't want to) change this include, and I need it because it defines my_function_from_big_include. Am I stuck ?


my_class_definition.h :

class MyClass
{
public:
   // I would like to keep it that way as it is mainly used in C++ files
   typedef enum
   {
      MY_ENUM_0,
      MY_ENUM_1,
      MY_ENUM_2
   } MyEnum;
};

Try 1 : my_c_function_definition.c :

#include "my_class_definition.h"

// I cannot remove this header
#include "big_hugly_include.h"

// foo is called in other C files
void foo()
{
   // I need to call this function with the enum from the C++ class
   // This doesn't work (class name scope does not exist in C)
   my_function_from_big_include(MyClass::MyEnum::MY_ENUM_0);
}

Try 2 : my_c_function_definition.cpp :

#include "my_class_definition.h"

extern "C"
{

// Error template with C linkage
#include "big_hugly_include.h"

// foo is called in other C files
void foo()
{
   // That would be ideal
   my_function_from_big_include(MyClass::MyEnum::MY_ENUM_0);
}

// end of extern "C"
}

Edited in response to @artcorpse

Try 3 : my_c_function_definition.cpp :

#include "my_class_definition.h"

// Error multiple definition of [...]
// Error undefined reference to [...]
#include "big_hugly_include.h"

extern "C"
{
// foo is called in other C files
void foo()
{
   // That would be ideal
   my_function_from_big_include(MyClass::MyEnum::MY_ENUM_0);
}

// end of extern "C"
}
Christophe
  • 68,716
  • 7
  • 72
  • 138
4nti7rust
  • 116
  • 10
  • 9
    If your enum is in a class, you can't access it from C. – Matthieu Brucher Mar 27 '19 at 08:02
  • 1
    don't think there is much you can do other than move/copy your enum into the global namespace – Alan Birtles Mar 27 '19 at 08:02
  • 1
    Why that `typedef enum ...` in C++ ? – bruno Mar 27 '19 at 08:07
  • your .h is not your real .h, since at least `class` or `struct` and `;` are missing. Are there other things that you've left out ? – Christophe Mar 27 '19 at 08:17
  • @Christophe Fixed. What do you mean by 'other things' ? – 4nti7rust Mar 27 '19 at 12:32
  • @bruno The type defined in the class is used as a type of class method argument. These methods are not shown in my example. – 4nti7rust Mar 27 '19 at 12:35
  • 1
    The duplicate provided to close this answer is IMHO not an appropriate one, since it doesn’t address the issue with types. – Christophe Mar 27 '19 at 16:44
  • @Christophe Is there anything I should do to get my question not tagged as duplicated ? – 4nti7rust Mar 27 '19 at 17:16
  • @4nti7rust I've aded two more duplicate, one about your template error message and one about enums. Together they should finally cover all your topics. – Christophe Mar 27 '19 at 19:29
  • @Christophe Thx, both questions have very interesting answers, but they still doesn't answer all my questions. I wanted to know if it was possible (and those two related question provide an answer), and if not, if there is a workaround (I don't have an answer to that in related questions). I see now that I should have asked only this second question. – 4nti7rust Mar 28 '19 at 11:19

2 Answers2

3

I want to use that enum in a C file. How can I do that?

Enum concept in C++ originates from C, so only thing you have to do is to isolate definition this enum from pure cpp API which is not known to C (remember about name mangling, see below).

Since C do not know in class/struct enums you can't use them. You have to define global scope enumeration or create such enumeration which will map C++ specific enumeration.

So create separate header file where shared API should be located. Do something like this:

// shared C, C++ header
#ifdef __cplusplus
extern "C" 
{
#endif

enum YourMagicEnum {
    YourMagicEnumAValue,
    YourMagicEnumBValue,
    YourMagicEnumCValue,
};

void someFunction(YourMagicEnum x);

#ifdef __cplusplus
} // extern "C"
#endif

Now this extern "C" is needed only for functions to disable name mangling (in C++ you can do function overloads, so compiler generates names which contain arguments type information).

When defining such function it should also have the extern "C" in front of that definition.

And remember in that header only C specific features and functions can be placed.

Also remember that VLA (Variable-length array) is in C standard, but not in C++ standard (most compiler support VLA for C++).

For more information see this page.

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • I will probably end up doing that, but I have only one C file using this class, everything else is C++ and I wanted to keep everything inside class namespace to avoid all my enum definition to be global (I really have a lot of them and it will quickly be very messy). – 4nti7rust Mar 27 '19 at 13:37
  • There are no namespaces in C or neither classes, so you can't use them if you need access API form C. – Marek R Mar 27 '19 at 13:40
  • I understand that, but is there a way to define a C type that is a copy of the one inside my class ? – 4nti7rust Mar 27 '19 at 13:44
  • only some script which will parse original file and generate respective C header. – Marek R Mar 27 '19 at 13:54
  • Ugly. Ok, I think I will just do it manually, hopefully when the code will evolve to more C++ we will get rid of it. I will wait a few more hours to see if someone else comes with another workaround, else I think your answer is the one that makes more sense. If you could rewrite your answer with the same namings as my example, and show how to include this type declaration back to the class, that would make it perfect ! – 4nti7rust Mar 27 '19 at 14:02
  • You can try invent some nasty macros, to handle that. But it could as painful as writing a script. – Marek R Mar 27 '19 at 14:24
1

Your Try2 is pretty close to a solution. Try to move the include outside extern "C". I usually just mark each function individually:

extern "C" void foo() 
{
...
}

This has the benefit of just exporting the one symbol as a C symbol, instead of trying to convert everything.

Tiberiu Maran
  • 1,983
  • 16
  • 23
  • That is a good proposal, but sadly I have linking errors when doing that (`Undefined reference` and `multiple definition`). Do you know what could create that (`big_hugly_include.h` is really full of ****) ? I have added try 3 in my question. – 4nti7rust Mar 27 '19 at 13:33
  • Unfortunately I don't think I can give too much insight without learning about this big_hugly_include.h. It sounds like a C++ header file, so it's most probably important for it to be outside the extern "C" block. The two types of errors you're mentioning sound like linking errors, so some of your other cpp files must be mismatched. Are you getting any errors related to "_foo"? – Tiberiu Maran Mar 27 '19 at 15:44
  • No error related to _foo, but I suspect this include to have mixed c and cpp header files. – 4nti7rust Mar 27 '19 at 15:46