Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forward declaring enum in C++ defined in C

I searched about forward declaration and didn't see any way to make my situation work. So here it is:

1) There is a C-header file, an export interface so to speak for a large multi-component software, that contains an enum typedef

"export.h":

// This is in "C"!
typedef enum _VM_TYPE {...., ...., ...,} VM_TYPE;

2) A part of the code, in C++, uses that export.

"cpp_code.cpp":

// This is in C++
#include "export.h"
#include "cpp_header.hpp"
{ .... using VM_TYPE values to do stuffs....}

"cpp_header.hpp":

// Need to somehow forward declear VM_TYPE here but how?
Struct VM_INFO {
....
VM_TYPE VType; //I need to add this enum to the struct
....
};

So quite obvious, the problem is in cpp_head.hpp, as it doesn't know about the enum.

I tried adding to cpp_header.hpp

typedef enum _VM_TYPE VM_TYPE;

and it'll actually work. So why does THIS work? Because it has C-style syntax?! Anyway, I was told to not do that ("it's C++, not C here") by upper "management".

Is there other way to make this work at all, based on how things are linked currently? They don't want to change/add include files; "enum class" is c++ only, correct? Adding just "enum VM_TYPE" to cpp_header.hpp will get error about redefinition.

Any idea? Thanks.

like image 665
Andrew Avatar asked Feb 18 '14 22:02

Andrew


People also ask

Can you forward declare enums?

Because enum definitions cannot reference one another, and no enum definition can cross-reference another type, the forward declaration of an enumeration type is never necessary. To make the code valid, you can always provide the full definition of the enum before it is used.

What is forward declaration in C?

In computer programming, a forward declaration is a declaration of an identifier (denoting an entity such as a type, a variable, a constant, or a function) for which the programmer has not yet given a complete definition.

Which is better #define or enum in C?

In C, enum is preferable only when we are working with natural group of constants. In all other cases it is #define and only #define .

Which is the correct way of declaring an enum?

The keyword 'enum' is used to declare new enumeration types in C and C++. Following is an example of enum declaration. // The name of enumeration is "flag" and the constant // are the values of the flag.


1 Answers

In the particular situation described in your question, you don't need to forward declare at all. All the files you #include are going to essentially get copy-pasted into a single translation unit before compilation proper begins, and since you #include "export.h" before you #include "cpp_header.hpp", then it'll just work, because by the time the compiler sees the definition of struct VM_INFO, it'll already have seen the definition of enum _VM_TYPE, so you've got no problem. There's basically no difference here between including "export.h" in "cpp_header.hpp", and including them both in "cpp_code.cpp" in that order, since you end up with essentially the same code after preprocessing. So all you have to do here is make sure you get your includes in the correct order.

If you ever wanted to #include "cpp_header.hpp" without including "export.h" in a translation unit where you need to access the members of struct VM_INFO (so that leaving it as an incomplete type isn't an option) then "export.h" is just badly designed, and you should break out the definition of anything you might need separately into a new header. If, as the comments suggest, you absolutely cannot do this and are required to have a suboptimal design, then your next best alternative would be to have two versions of "cpp_header.hpp", one which just repeats the definition of enum _VM_TYPE, and one which does not. You'd #include the first version in any translation unit where you do not also #include "export.h", and #include the second version in any translation unit where you do. Obviously any code duplication of this type is inviting problems in the future.

Also, names beginning with an underscore and a capital letter are always reserved in C, so you really shouldn't use them. If a future version of C ever decides to make use of _VM_TYPE, then you'll be stuck with either using an outdated version of C, or having all this code break.

like image 193
Crowman Avatar answered Oct 05 '22 14:10

Crowman