21

Forward declaration of enums in C does not work for me. I searched the internet and Stack Overflow but all of the questions regarding forward declarations of enumerators refer to C++. What do you do for declaring enumerators in C? Put them at the top of each file (or in a header) so that all functions in the file can access them?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
loop
  • 3,460
  • 5
  • 34
  • 57

4 Answers4

14

Put them in a header so that all files that need them can access the header and use the declarations from it.

When compiled with the options:

$ /usr/bin/gcc -g -std=c99 -Wall -Wextra -c enum.c
$

GCC 4.2.1 (on MacOS X 10.7.1) accepts the following code:

enum xyz;

struct qqq { enum xyz *p; };

enum xyz { abc, def, ghi, jkl };

Add -pedantic and it warns:

$ /usr/bin/gcc -g -std=c99 -Wall -Wextra -pedantic -c enum.c
enum.c:1: warning: ISO C forbids forward references to ‘enum’ types
enum.c:5: warning: ISO C forbids forward references to ‘enum’ types
$

Thus, you are not supposed to try using forward declarations of enumerated types in C; GCC allows it as an extension when not forced to be pedantic.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Why exactly ISO C forbids forward references to ‘enum’ types? – pmor Feb 04 '22 at 13:51
  • Because until the compiler knows the definition, it can't be sure how big the storage needs to be. It might be possible to store the values in 1-byte integers (`char`) or it might require 2 or 4 bytes. – Jonathan Leffler Feb 04 '22 at 13:58
6

You can't "forward-declare" enums because the compiler won't know the size of the enum. The C standard says " Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration".

Foo Bah
  • 25,660
  • 5
  • 55
  • 79
  • Isn't it more likely that it isn't allowed because it just don't make any cotton-pickin' sense! You can't refer to any of the enum NAMES until you tell the compiler what they are. Of what possible use is an enum that defines no names? – luser droog Sep 20 '11 at 05:29
  • 5
    @luser: You could, just about, make a case that a pointer to an incomplete enum (as in my example code) makes some sort of sense. But it is pretty tenuous -- your conclusion that they are of essentially no practical use when incomplete is correct. – Jonathan Leffler Sep 20 '11 at 07:37
  • 6
    @luserdroog you can use an incomplete definition of a struct in header files, so likewise you could have an incomplete definition of an enum backed up by a definition elsewhere, and having that definition included at every point of use of enum values. – wds Mar 17 '14 at 10:15
  • @luserdroog. My use case was (in a header): `enum Foo { ... }; enum Bar; enum Foo bar2foo( Bar bar );` So we declare function which returns a Foo. If you want to use it, you'll also need to include the definition of Foo. – Martin Bonner supports Monica Dec 11 '14 at 14:23
  • 11
    This is not an argument. `typedef struct S S;` works, but `typedef enum E E;` doesn't, despite both having undefined sizes. Actually, forward declarations are just about _not_ knowing the sizes of the involved entities. – alecov Apr 07 '15 at 21:15
  • It is not only because of size but because you'll not know the compatible type of the *pointers* and hence the representation if you use the typedef in pointers. – Antti Haapala -- Слава Україні Dec 01 '19 at 04:05
0

I came here having the same error, but there is not really much information provided here on the code/error.

My Makefile-flags are: -Wall -Wextra -Werror -pedantic -std=c17

In my header I have the following enum:

typedef enum 
{
  IS_HEAD = 1, 
  IS_VALUE = 2,
  IS_SIDE
} CoinResult;

The tutorials here and there

Would recommend to use something like this:

enum CoinResult cr;
cr = IS_SIDE;

This results in the error stated by the OP.

Solved by using:

CoinResult cr = IS_SIDE; 

Not sure which C-Standard, Code or reference OP was using, but I somewhat agree: Most tutorials and solutions for this relatively simple issue are kinda ambiguous.

Qohelet
  • 1,459
  • 4
  • 24
  • 41
  • If the variable definition and the subsequent assignment are at file scope, then the error is simply that you can't have random assignments at file scope. A translation unit consists of a sequence of 'external declarations', which may be function definitions or declarations. The assignment `cr = IS_SIDE;` is neither a function definition nor a declaration. The initialized declarations is a declaration (and a definition). If your definition/assignment combo occurs inside the scope of a function, we need to see an [MCVE] of the problem. – Jonathan Leffler Apr 18 '22 at 14:46
-1

CoinResult isn't an enum, it's a type. If you had

enum CoinResult {
    IS_HEAD = 1,
    IS_VALUE = 2,
    IS_SIDE,
};

then

    enum CoinResult cr;

would be correct.