2

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.

Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
SmallX
  • 89
  • 7
  • 3
    The names RAD_ALLOWED, RAD_STOPPED and RAD_OFF are in no way linked to the names Values_E and Values_X. Both these header files are defining the names RAD_ALLOWED, RAD_STOPPED and RAD_OFF. – user253751 Mar 07 '23 at 19:17
  • 3
    C doesn't differentiate enum names by enum type. They're simply a named integer constant. You'll have to rename your enum value names. – Marco Mar 07 '23 at 19:18
  • 5
    So when you use `RAD_ALLOWED` in your source code, which enumeration do you think it uses? – Caleb Mar 07 '23 at 19:18
  • 1
    @EricPostpischil It can give you a warning if you actually have a variable of an enum type and assign it an enum value from a different enum type. This is one of my least favorite design decisions in the C language. Having used a language where enums values *are* tied to the type is just so much cleaner. – Jason Mar 07 '23 at 19:33
  • 1
    O.T.: If you want an alias of an `enum` (they are identical) you can use `typedef Values_E Values_X;` – David Ranieri Mar 07 '23 at 19:34
  • @Jason: Re “a variable of an enum type and assign it an enum value from a different enum type”: That is a different issue. I spoke to assigning an enumeration constant to an enumeration variable, not to assigning an enumeration variable to an enumeration variable. – Eric Postpischil Mar 07 '23 at 19:36
  • @Caleb I don't kwow which one it's used, i'm doing simply something like if(var == RAD_ALLOWED){} and the RAD_ALLOWED is underlined by red and also my two enumeration in different files. i wan't to use only one of them but as other functions that i'm using are in both included files i have to keep them – SmallX Mar 07 '23 at 19:39
  • 3
    Re “when i include both header files in the same c file”: Well, there is a solution: Do not do that. Whatever is automatically generating these things did not intend for both headers to be included in the same C source code file. So do not include them both in one file. Put your routines using one header in one file, your routines using the other header in another file. Anything that needs to use both can be in a third file that calls the routines in the first two files. – Eric Postpischil Mar 07 '23 at 19:50
  • @EricPostpischil, I see what you mean this may be a solution, but there are some functions in my C file that uses other content from both header file apart the famous two enumeration... So lot of adaptation to consider in this case and i'm sure that in some cases i won't be able to split because they are linked – SmallX Mar 07 '23 at 19:57
  • 1
    @EricPostpischil I went back in history to see where my misconceptions were coming from. And found this in K&R (emphasis added) *"Although variables of enum types may be declared, compilers **need not check** that what you store in such a variable is a valid value for the enumeration. Nevertheless, enumeration variables **offer the chance of checking** and so are often better than #defines"* So you are correct, and I have deleted my comments. – user3386109 Mar 07 '23 at 20:01
  • @SmallX *I don't kwow which one it's used* That's the point -- the compiler has no way to differentiate between the two. – Caleb Mar 07 '23 at 23:01
  • Does this answer your question? [Two enums have some elements in common, why does this produce an error?](https://stackoverflow.com/questions/2161940/two-enums-have-some-elements-in-common-why-does-this-produce-an-error) – Cristik Mar 08 '23 at 06:20

3 Answers3

5

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • @EricPostpischil I could be wrong, but I believe enums will always have `int` backing unless given the packed attribute (or `-fshort-enums`). – Jason Mar 07 '23 at 19:37
  • 1
    @Jason: C 2018 6.7.2.2 4 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…” – Eric Postpischil Mar 07 '23 at 19:38
  • 1
    @EricPostpischil I stand corrected =]. All platforms I have used (including embedded) default to `int` unless I force it otherwise, but that is anecdotal. – Jason Mar 07 '23 at 19:40
  • This should work since the values are constant anyway (but renaming one header file should be enough). – Miguel Sandoval Mar 07 '23 at 20:26
1

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"
  • @Michel, i'm using them without specifying them. The exemple you are giving me doesn't represent my case. I have the same names in the enumeration content – SmallX Mar 07 '23 at 19:44
  • @SmallX Check John's answer https://stackoverflow.com/a/75666403/15246308 – Miguel Sandoval Mar 07 '23 at 20:22
1

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.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335