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
, orenum
); struct
andunion
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.