Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forward declaring an enum in C headers used in C++ code

Tags:

c++

c

You can't forward declare an enum in C++, but you can in C.

For a C code-base that uses some C++ code, is there a way to use a forward declared enum in C that doesn't cause errors when that header is used in C++ (within an extern "C" {..} block)?

Example:

extern "C" {
    enum MyEnum;
}
int main() { return 0; }

GCC gives the error:

error: use of enum ‘MyEnum’ without previous declaration
  enum MyEnum;
       ^~~~~~

Clang also fails with:

error: ISO C++ forbids forward references to 'enum' types
        enum MyEnum;

To give some context, this is a mainly C code-base where a small C++ module happens to include a header for C code. I can do some hack to make C++ ignore the enum, but I would like to know if its possible for C++ to use C headers in this case.


Update: It's been noted the official C specification doesn't support this. However, it seems this is a de facto standard among some of the most widely used compilers: GCC, Clang, and Microsoft Visual C++.

like image 679
ideasman42 Avatar asked Aug 24 '17 02:08

ideasman42


2 Answers

Forward declaration of enums in C just makes no sense. Enums in C only introduce integral enumeration constants. They don't introduce any types you would want to use. Each enum type is an unspecified integral type, compatible with all other integral types, so there isn't any type safety at all.

typedef enum e12 { ONE, TWO } e12;
typedef enum e34 { THREE, FOUR } e34;
int main () {
    e12 one = ONE;
    e34 three = THREE;
    one = three;
    three = ONE;
    return one + three;
}

This C program compiles cleanly with GCC on -Wall -Wextra -Wpedantic (it won't work as a C++ program of course).

So a useful portable cross-language solution would be

#ifdef __cplusplus
   enum MyEnum : int;
#else
   typedef int MyEnum; // 'enum MyEnum' would give no improvement over this
#endif
like image 93
n. 1.8e9-where's-my-share m. Avatar answered Oct 26 '22 22:10

n. 1.8e9-where's-my-share m.


You can forward-declare enum in C++ starting from C++11. It's called "opaque declaration" rather than "forward declaration" because technically it results in a bit different effect: the size of the enum is known after its opaque declaration, while with the forward-declared types that's not the case.

However, from the daily perspective it's the same idea: you can just declare your enum and use it further in the code. From cppreference:

enum-key attr(optional) nested-name-specifier(optional) identifier enum-base(optional) ;(2) (since C++11)

2) Opaque enum declaration: defines the enumeration type but not its enumerators: after this declaration, the type is a complete type and its size is known. Note: an explicit specialization declaration of a scoped enumeration member of a class template is the only case where nested-name-specifier appears before identifier (since C++14)

like image 30
Vasiliy Galkin Avatar answered Oct 26 '22 22:10

Vasiliy Galkin