prelic
prelic

Reputation: 4518

Enumeration Scope

If I have enums like:

enum EnumA
{
  stuffA = 0
};
enum enumAA
{
  stuffA = 1
};

What happens here when you refer to stuffA? I thought you would refer to them like EnumA.stuffA and EnumB.stuffA as in Java, but that doesn't seem to be the case in C.

Upvotes: 13

Views: 8004

Answers (6)

Eric Postpischil
Eric Postpischil

Reputation: 222526

This answer shows how the rules of C 2018 preclude the same identifier from being used as a member of two different enumerations. It is a language-lawyer view, intended to show how this requirement arises out of the language of the standard.

6.2.3, “Name spaces of identifiers,” tells us:

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).

Thus, all enumerator constants and ordinary declarators exist in one name space. (The name spaces omitted above are for labels [for goto statements]; tags of structures, unions, and enumerations [the name after a struct, as in struct foo]; and members of structures or unions [each has its own name space]).

6.7, "Declarations," tells us in paragraph 5 that:

A definition of an identifier is a declaration for that identifier that:

for an enumeration constant, is the (only) declaration of the identifier;

So the standard indicates that there is only one definition of an enumeration constant. Additionally, 6.2.1, “Scopes of identifiers,” tells us in paragraph 1:

An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter. The same identifier can denote different entities at different points in the program. A member of an enumeration is called an enumeration constant.

Observe that this tells that if foo identifies an enumeration constant, it identifies a member of an enumeration—it is a particular member of a particular enumeration. It cannot identify both a member of enum A and a member of enum B. Therefore, if we had the code:

enum A { foo = 1 };
enum B { foo = 1 };

at the point where foo appears the second time, it is an identifier for foo in enum A, and therefore it cannot be a member of enum B.

(The sentence about an identifier denoting different entities at different points is introducing the concept of scope. Further paragraphs in that clause explain the concept of scope and the four kinds of scope: function, file, block, and function prototype. These do not affect the above analysis because the code above is within one scope.)

Upvotes: 1

Mike
Mike

Reputation: 1

Depending on where you declare these enums, you could also declare new scopes using the namespace keyword.

NOTE: I wouldn't recommend doing this, I'm just noting that it's possible. Instead, it would be better to use a prefix as noted in the other examples.

namespace EnumA
{
    enum EnumA_e
    {
        stuffA = 0
    };
};

namespace EnumAA
{
    enum enumAA_e
    {
        stuffA = 1
    };
};

Upvotes: -1

Jens Gustedt
Jens Gustedt

Reputation: 78903

As the others already said enumeration constants must be unique in the actual scope where they are defined. But with them as with other identifiers it is allowed to redefine them in another scope. Eg.

enum EnumA
{
  stuffA = 0
};

void func(void) {
   enum enumAA
   {
     stuffA = 1
   };
   // do something
}

would be fine. But such redefinitions in different scopes are often frowned upon and should be well documented, otherwise you will quickly loose yourself and others.

Upvotes: 6

NPE
NPE

Reputation: 500317

enums don't introduce new scope.

In your example, the second enum wouldn't compile due to the stuffA name clash.

To avoid name clashes, it is a common practice to give the elements of an enum a common prefix. Different prefixes would be used for different enums:

enum EnumA
{
  EA_stuffA = 0
};
enum EnumAA
{
  EAA_stuffA = 1
};

Upvotes: 10

Joseph Stine
Joseph Stine

Reputation: 1022

As mentioned, this won't compile because stuffA is defined twice. Enum values are simply referred to by the enumeration (that is "stuffA" rather than EnumA.stuffA). You can even use them on types that aren't enums (such as integers). Enums are sometimes used this way with ints, similar to the way one would #define constants.

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 753675

The enumeration constants are in the global name space (more precisely, the ordinary identifiers name space, contrasted with the labels, tags, and structure/union member namespaces), so you get a compilation error on the second stuffA.

You cannot use two different values for the same enumeration name (nor the same value specified twice) in a single translation unit.

Upvotes: 7

Related Questions