Why does C allow the use of enum as a variable? - c

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 ?

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.

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 */

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

Accessing an enum inside a struct in C

#include <stdio.h>
typedef struct test {
enum en {
zero, one
} en;
} test;
int main(){
test t;
// t.en = test::one; <-- How can I accomplish this?
return 0;
}
test::one is a C++ syntax and won't compile in C.
Is it possible to access en from outside the struct in C?
I know I can use integers here like t.en = 1; but I'm trying to use enum values.
In C, a struct does not create a new namespace for types - the fact that you defined enum en within the body of the struct definition makes no difference, that tag name is visible to the remainder of the code in the program. It's not "local" to the struct definition. Same with a nested struct type - if declared with a tag, such as
struct foo {
struct bar { ... };
...
};
struct bar is available for use outside of struct foo.
C defines four types of namespaces - one for all labels (disambiguated by the presence of a goto or :), one for all tag names (disambiguated by the presence of the struct, union, or enum keywords), one for struct and union member names (per struct or union definition - disambiguated by their presence in a struct or union type definition, or by the presence of a . or -> member selection operator), and one for all other identifiers (variable names, external (function) names, typedef names, function parameter names, etc.).
Yes, by simply writing the name defined.
#include <stdio.h>
typedef struct test {
enum en{
zero, one
} en;
} test;
int main(){
test t;
t.en = one;
return 0;
}
Structure do not introduce a separate scope in C.
Note also that using en as both the enum tag and variable name is perfectly fine in C, but somewhat confusing in C++.
Here is a modified version that should compile as C and C++:
#include <stdio.h>
#ifdef __cplusplus
#define SCOPED_ENUM(s,e) s::e
#else
#define SCOPED_ENUM(s,e) e
#endif
typedef struct test {
enum en {
zero, one
} en;
} test;
int main() {
test t;
t.en = SCOPED_ENUM(test, one);
return 0;
}

How to access enum defined within a struct in C program

I am new to the C language and struggling with how to access enum's within a struct.
My code is the following:
bankHeader.h File
struct bankAcct{
int amount;
enum typeOfAcc{chck = 0, saving = 1};
int balance;
}
bank.c File
#include <stdio.h>
#include "bankHeader.h"
struct bankAcct test;
test.amount=100;
// I want to be able to get the value within my typeOfAcc
// example something like test.typeOfAcct = "chck" should return 0;
I reviewed some of the forms but I dont see anything that was easy to understand or worked.
If the enum is meant to be local to the struct, use an anonymous enum:
struct bankAcct{
int amount;
enum {chck = 0, saving = 1} type_of_acct;
int balance;
};
You could also put a tagged enum inside the struct:
struct bankAcct{
int amount;
enum typeOfAcc {chck = 0, saving = 1} type_of_acct;
//^this misleadingly puts `enum typeOfAcc` in filescope
int balance;
};
but a tagged (as opposed to an anonymous one) inner definition of an enum (or struct or union) will be hoisted. In effect, the latter snippet is just a confusing way of doing:
enum typeOfAcc {chck = 0, saving = 1};
struct bankAcct{
int amount;
enum typeOfAcc type_of_acct;
int balance;
};
Note that as peter-reinstate-monica points out in his comment below, the chck and saving constants will be "hoisted" regardless of whether or not you choose to use an anonymous embedded enum type.
Every field in your struct declaration is in the form
type fieldName;
With
enum typeOfAcc{chck = 0, saving = 1};
you have specified the type... but not the field name. That's just like defining a structure in this way
struct foo {
int;
}
So, basically, what you need is a field name:
struct bankAcct{
int amount;
enum typeOfAcc{chck = 0, saving = 1} type;
int balance;
}
You will be able to access it with
struct bankAcct var;
printf("%d\n", var.type);
Addendum
I would not recommend defining an enumeration inside a struct, first of all for readability reasons. Another reason might be incompatibility with C++: I wasn't able to compile an example C++ code in which the symbols of the inner enum were accessed. The following assignment
struct bankAcct var;
var.type = chck;
raised an error on gpp because the symbol chck could not be referenced outside the struct definition scope. Even assigning an integer to the enum field lead the compiler to complain, and I could not even perform the casting
b.type = (enum typeOfAcc) 1;
because an error was raised: the enum typeOfAcc wasn't be accessible as well.
But in C these assignments would be ok, and both enum tags and constant identifiers (named and anonymous) would be "reachable". As explained in C specification 6.2.1§4, the scope of an identifier outside any code block is the whole translation unit:
Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit.
Just for completeness, after saying where the scope ends, we must say where the scope begins (C specification 6.2.1§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.
You should declare the enum type outside the structure, then declare a member variable with that type.
typedef enum {
chck = 0,
saving = 1
} accountType;
struct bankAcct{
int amount;
accountType typeOfAcc ;
int balance;
}

typedef struct but keep new type namespaced under keyword 'struct'

How can I typedef a struct but still keep the new type namespaced under the keyword 'struct'?
example:
struct foo {
int x;
};
typedef struct foo struct bar;
int main(void) {
struct bar bar;
bar.x = 10;
return 0;
}
but this doesn't work obviously.
Here are the errors if anyone is curious:
main.c:5:20: error: two or more data types in declaration specifiers
typedef struct foo struct bar;
^
main.c:5:27: warning: useless storage class specifier in empty declaration
typedef struct foo struct bar;
^
main.c: In function 'main':
main.c:9:13: error: storage size of 'bar' isn't known
struct bar bar;
How can I typedef a struct but still keep the new type namespaced under the keyword 'struct'?
So, it seems that you want to define a structure alias for another structure type.
This is not possible with typedef as it creates a single word alias. The new alias can't be consisted of multiple white space separated words.
But you can use a single name like struct_bar with struct implemented inside of the name to show that bar is a structure.
#include <stdio.h>
struct foo {
int x;
};
typedef struct foo struct_bar;
int main(void) {
struct_bar bar;
bar.x = 10;
return 0;
}
How can I typedef a struct but still keep the new type namespaced under the keyword 'struct'?.
You cannot. A namespace is a declarative region that provides a scope to the identifiers (names of the types, function, variables etc) inside it. The concept of Namespace as it is defined within C++, is not inherent in C.
So, if you are okay with minor changes in your requirements, instead of doing something unnatural, use a simple typedef:
Instead of this:
struct foo {
int x;
};
do this:
typedef struct {
int x;
}foo;
Then this will work:
typedef foo bar;
int main(void )
{
bar b;
b.x = 10;
return 0;
}
Note: Although namespaces are not inherent in in C, as they are in C++, there are some interpretations eg: as discussed here, that argue the point.
C doesn't have any type of support for namespaces (at least not in the sense that C++ does).
When you create a typedef, the new type name is a single identifier, not multiple words. So struct bar can't be an alias for another type. You would have to call it bar or some other one-word name.
You can't. This isn't how it works.
You cannot "create" a type whose name is more than one word, nor can you refer to a type alias using the keyword struct.
The purpose of writing struct, in this context, is to refer to a struct type by a name that wasn't introduced as an alias. The keyword is there to say that that's what you want to do. But it's not part of the name; it cannot be part of the name.
Fortunately, there's no reason to need or even want this.
I found a solution that works for cygwin:
struct foo {
int x;
};
struct bar {
struct foo;
};

what is "struct <name_1> <name_2>" in c?

there is a line in c code:
struct name_1 name2;
what this line implies?
my understanding about above line is name_1 is the name of the structure and name2 is the object variable. However name_1 should have been defined somewhere, but I could not find the definition of name_1.
so my question is; is there anything like this where we can have an object of a structure which is not defined anywhere.
At file scope, this is the definition of a variable called name2 whose type is struct name_1. If there has not been a previous declaration of struct name_1; then this line also declares that type.
Being a file scope variable definition with no initializer nor storage class specifier, this is a tentative definition. Tentative definitions may have incomplete type so long as the type is completed by the end of the file, e.g.:
#include <stdio.h>
struct foo bar;
void f();
int main()
{
printf("%p\n", (void *)&bar);
f();
// cannot do this
// printf("%d\n", bar.x);
}
struct foo { int x; };
void f()
{
bar.x = 5;
}
This sort of code would be uncommon however. If you see struct foo bar; in real code it is more likely that struct foo was previously defined somewhere that you are overlooking.
Is there a header file (name.h) you have included in your c code? Usually, structure, constant and function declarations are in the header file, which is 'included' (at the top of your c file), and you could then use those structures and constants in your c file without defining them

declaration does not declare anything : warning?

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int main()
{
struct emp
{
struct address
{
int a;
};
struct address a1;
};
}
This code shows a warning:-
warning : declaration does not declare anything (enabled by default)
Where as the following code shows no warning
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int main()
{
struct emp
{
struct address
{
int a;
}a1;
};
}
Why 'warning' is displayed in the first code only?
The reason why the compiler is showing the warning is because it doesn't see a name for the variable of type address you defined for the emp struct, even though you do declare something using address on the next line, but I guess the compiler is not smart enough to figure that out.
As you showed, this produces a warning:
struct emp {
struct address {}; // This statement doesn't declare any variable for the emp struct.
struct address a1;
};
But not this:
struct emp {
struct address {} a1; // This statement defines the address struct and the a1 variable.
};
Or this:
struct address {};
struct emp {
struct address a1; //the only statement declare a variable of type struct address
};
The struct emp {} doesn't show any warnings since this statement is not inside a struct defintion block. If you did put it inside one of those then the compiler will show a warning for that as well. The following will show two warnings:
struct emp {
struct phone {};
struct name {};
};
The reason the warning is displayed is that the first excerpt is not proper C - it has a constraint violation that a standards-compliant C compiler must produce a diagnostisc message for. It violates the C11 6.7.2.1p2:
Constraints
A struct-declaration that does not declare an anonymous structure or anonymous union shall contain a struct-declarator-list.
Meaning that it is OK to write
struct foo {
struct {
int a;
};
};
since the inner struct declares an anonymous structure, i.e. it is not named.
But in your example the struct address has a name - address - and therefore it must have a declarator list after the closing brace - declarator list being for example a1 as in your example, or more complex foo, *bar, **baz[23][45].
The syntax of a structure definition is:
struct identifier {
type member_name;
// ...
};
If you add an identifier just after the closing curly brace, you're declaring a variable with that defined struct.
In your first example the compiler consider the address struct as member type. it's like if you writes:
struct identifier {
type ; // No member name is specified
type a1;
// ...
}
But in the second example you specified the member name:
struct identifier {
type a1; // Member name specified
// ...
}
And here is an example of the warning: http://ideone.com/KrnYiE.
Going to also throw this out there that this error may also show up if you don't properly forward declare types found in other namespaces.
https://stackoverflow.com/a/19001722/1330381
Example
namespace A {
// forward declarations
namespace X {
namespace Y {
class MyType;
}
}
namespace B {
class Foo() {
void methodBar(const X::Y::MyType& mt);
}
}
In my case, i had the same warning because the structure name was previously used and changing the structure name solved the problem.

Resources