Home > Blockchain >  Why does C allow the use of enum as a variable?
Why does C allow the use of enum as a variable?

Time:12-14

How can C compile and run the following code without errors ?

#include <stdio.h>

enum
{
    DETAILS_A                       =0x00U,
    DETAILS_B                       =0x01U,
    DETAILS_C                       =0x02U
}u8_Details;

int main()
{
    
    u8_Details = 42;
    
    printf("%d\n\n", u8_Details);
    
    printf("%d", DETAILS_B);

    return 0;
}

Console ouput:

42

1

...Program finished with exit code 0
Press ENTER to exit console

If I understand correctly what's happening here, it's like this line:

u8_Details = 42;

was equivalent to this :

u8_Details u8_Details = 42;

But that just seems so wrong. What am I missing ?

CodePudding user response:

In this declaration

enum
{
    DETAILS_A                       =0x00U,
    DETAILS_B                       =0x01U,
    DETAILS_C                       =0x02U
}u8_Details;

you declared the variable u8_Details of an unnamed enumeration type in the file scope.

You may assign a value to the variable as to any other mutable variable.

As for your assumption

u8_Details u8_Details = 42;

then it is wrong. u8_Details is not a type specifier. It is an identifier of a variable of an unnamed enumeration type.

CodePudding user response:

u8_Details is not the enum (type) but a variable of that enum (type).

enum {...} foo;

is a variable definition statement. The enum {...} is the type, and foo is the identifier.

if you want make foo a type, use typedef:

typedef enum {...} foo; /* foo is an alias of type enum {...} now */
foo bar; /* bar is of type foo */

CodePudding user response:

Vlad answered the question correctly, but I want to add something:

C has four different name spaces for identifiers:

  • label names (disambiguated by goto and :);
  • tag names (disambiguated by struct, union, or enum);
  • struct and union member names (disambiguated by . or -> operators and presence in a definition);
  • all other identifiers (variable names, function names, typedef names, enumeration constants, etc.);

The same identifier can be used in different names spaces in the same scope - IOW, the following is perfectly legal (just really bad practice):

int main( void )
{
  struct foo {   // tag namespace
  {
    int foo;     // member namespace
    int bar;
  } foo;         // all other identifiers namespace
  
  goto foo;      // label namespace
  ...
  foo:           // label namespace
  foo.foo = 1;   // all other identifiers and member namespaces
  ...
}

The identifier foo can be used as a struct tag name, a struct member name, a label, and a variable name, all in the same scope.

Each struct or union definition creates a new member namespace, so you can use foo as a member name in different struct or union definitions:

 struct a { int foo; ... };
 struct b { double foo; ... };

Enumeration constants and typedef names belong to the "all other identifiers" namespace, so if you use foo as an enumeration constant, you cannot also use it as a regular variable name or function name or typedef name in the same scope (and vice versa).

There is only one tag namespace, so you can't use the same tag name for a struct type and a union type in the same scope - IOW, if you have struct foo, you cannot also have union foo and enum foo in the same scope.

  • Related