Redeclaration of enumeration problem in C

1.3k Views Asked by At

I'm having a compilation error in my C project. I have a header file that contains this enumeration:

typedef enum {
  RAD_ALLOWED= 0,         
  RAD_STOPPED ,
  RAD_OFF 
} Values_E;

and in another header file with this enum:

typedef enum {
  RAD_ALLOWED= 0,         
  RAD_STOPPED ,
  RAD_OFF 
} Values_X;

when I include both header files in the same c file I'm having errors similar to:

214: error: previous definition of 'RAD_STOPPED ' was here
129: error: redeclaration of enumerator 'RAD_STOPPED '

Yes, the content of both enumeration is the same but names are different so i don't understand why do i have this problem. Note that the both header files that contains those enumeration are automatically generated so I can't change their content.

3

There are 3 best solutions below

4
John Bollinger On BEST ANSWER

Yes, the content of both enumeration is the same but names are different so i don't understand why do i have this problem.

The problem is not a clash of the enumeration names, it is a clash of the names of the enumeration constants they declare. The names of enumeration constants live in the namespace of ordinary identifiers, so they must be distinct across all in-scope enumeration definitions. And that makes sense in light of the fact that you use them without reference to the enumeration that defines them.

Note that the both header files that contains those enumeration are automatically generated so i can't change their content.

If you use only the enum constants and not the enum types, then you can just choose one of the enum definitions to include, and omit the other. For example, #include "values_e.h" but ignore values_x.h. The two enum definitions shown will produce enum constants corresponding to the same values, so if only the values of the constants matter then it doesn't matter which enum you get them from. This may be easier said than done, however, if any of the other headers you are using themselves include the enum definitions indirectly.

Or possibly you can split your code so that no one source file needs to reference both enum types.

Otherwise, your next best bet would be to change your code generator so that it doesn't yield name clashes.

Or if you can't do that, then you could possibly apply some macro grease to effect a local renaming, like this:

// Beginning of file

#define RAD_ALLOWED E_RAD_ALLOWED
#define RAD_STOPPED E_RAD_STOPPED
#define RAD_OFF E_RAD_OFF
#include "values_e.h"
#undef RAD_ALLOWED
#undef RAD_STOPPED
#undef RAD_OFF

#define RAD_ALLOWED X_RAD_ALLOWED
#define RAD_STOPPED X_RAD_STOPPED
#define RAD_OFF X_RAD_OFF
#include "values_x.h"
#undef RAD_ALLOWED
#undef RAD_STOPPED
#undef RAD_OFF

// everything else ...

Within that source file, you then use the E_* and X_* versions of those identifiers instead of the unprefixed ones. There are potential gotchas with that, but it's worth a shot if you don't have a better alternative.

2
Miguel Sandoval On

Enumerations are global symbols in C. The name you give to them has no effect, in fact, you can use them without specifying them:

enum some_name {A = 1}; // with name
enum {B = 2};  // without name

int x = A + B; // you don't have to specify the name of the enum
printf("%d", x); // 3

If you cannot modify the header files, then your best option is the answer @JohnBollinger posted (however, you just have to modify the names in one header file (any), not both):

#define RAD_ALLOWED RAD_ALLOWED_1
#define RAD_STOPPED RAD_STOPPED_1
#define RAD_OFF RAD_OFF_1

#include "header1.h"

#undef RAD_ALLOWED
#undef RAD_STOPPED
#undef RAD_OFF

#include "header2.h"
0
Vlad from Moscow On

From the C Standard (6.2.3 Name spaces of identifiers)

1 If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. Thus, there are separate name spaces for various categories of identifiers, as follows: — all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants).

and (6.2.1 Scopes of identifiers)

7 Structure, union, and enumeration tags have scope that begins just after the appearance of the tag in a type specifier that declares the tag. Each enumeration constant has scope that begins just after the appearance of its defining enumerator in an enumerator list. Any other identifier has scope that begins just after the completion of its declarator.

So having these two declarations of enumerations in the same translation unit and in the same scope (file scope)

typedef enum {
  RAD_ALLOWED= 0,         
  RAD_STOPPED ,
  RAD_OFF 
} Values_E;

and

typedef enum {
  RAD_ALLOWED= 0,         
  RAD_STOPPED ,
  RAD_OFF 
} Values_X;

results in redeclarations of the enumeration constants. So the compiler issues error messages relative to each enumerator name that is present in the both enumerations.