How to access enum defined within a struct in C program - c

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;
}

Related

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

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.

How to find all assignment expressions of a certain type

Say I have some struct definition like
struct sql_subtype {
sql_type *type;
unsigned int digits;
unsigned int scale;
}
This struct sql_subtype is used all over the place in my codebase which is huge. Objects of this type are often members of other objects. So simple string matching is not good enough to find the assignment locations. Is there some nice trick or open source static-analysis tool that can give me the locations in the code base where any object of this type is being set to some value? Find all locations similar to
struct sql_subtype type1 = type2;
or
c1->t = c2->t; // where the t's are of the type of interest.
etc.
The general problem: given the class of expressions that involve a certain operator that returns a certain type, how can I find all statements that contain expressions of this class?
Not a general solution, but there is a way to find the struct assignments with the C compiler alone. C allows you to declare members of struct as const, so you can add an extra member to the struct that is declared as const and only assignments will fail:
struct sql_subtype {
unsigned int digits;
unsigned int scale;
const unsigned int poison_pill;
};
void function_call(struct sql_subtype foo) {
struct sql_subtype initialized_from_copy = foo;
initialized_from_copy.digits = 42;
struct sql_subtype another = {0};
another = foo;
}
// if the const member is the last one even initializer lists will work!
struct sql_subtype initialized = {1, 2};
int main(void) {
function_call(initialized);
}
compile with GCC, and the only diagnostics you get are
constmemberhack.c: In function ‘function_call’:
constmemberhack.c:10:13: error: assignment of read-only variable ‘another’
another = foo;
^

Enum within struct - Scope of enum in C [duplicate]

Why are enum values accessible outside the block in which enum is defined in C, but not in C++?
Consider the following C program.
#include <stdio.h>
struct mystruct
{
enum {INT, FLOAT, STRING} type;
int integer;
float floating_point;
} tu;
/* Why is INT accessible here? */
int main()
{
tu.type = INT;
tu.integer = 100;
return 0;
}
It compiles and runs fine in C.
But in C++ it fails in compilation.
#include <iostream>
struct mystruct
{
enum {INT, FLOAT, STRING} type;
int integer;
float floating_point;
} tu;
/* Why is INT accessible here? */
int main()
{
tu.type = INT;
tu.integer = 100;
return 0;
}
[Error] 'INT' was not declared in this scope
Are enum and scope rules different in C and C++?
In C, there is simply no rule for scope for enums and struct. The place where you define your enum doesn't have any importance.
In C++, define something inside another something (like an enum in a class) make this something belong to the another something.
If you want to make your enum global in C++, you will have to define it outside your class, or access from your struct path:
#include <iostream>
struct mystruct
{
enum {INT, FLOAT, STRING} type;
int integer;
float floating_point;
} tu;
int main()
{
tu.type = mystruct::INT; // INT is not in global scope, I have to precise it.
tu.integer = 100;
return 0;
}
Note: This works in this exemple, because you are using a struct, where everything is public by default. Be careful; you can access your enum type and values from outside your struct or your class only if the enum is in a public scope, as any field or function.
The main difference is that opposite to C, C++ has a class scope.
In C (6.2.1 Scopes of identifiers)
4 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.
Thus in this program
#include <stdio.h>
struct mystruct
{
enum {INT, FLOAT, STRING} type;
int integer;
float floating_point;
} tu;
/* Why is INT accessible here? */
int main()
{
tu.type = INT;
tu.integer = 100;
return 0;
}
Enumerators INT, FLOAT, STRING are declared outside any block scope and therefore have the file scope.
In C++ there is defined a separate scope - class scope:
3.3.7 Class scope
1 The following rules describe the scope of names declared in classes.
1) The potential scope of a name declared in a class consists not only
of the declarative region following the name’s point of declaration,
but also of all function bodies, default arguments,
exception-specifications, and brace-or-equal-initializers of
non-static data members in that class (including such things in nested
classes).
and
2 The name of a class member shall only be used as follows:
— in the scope of its class (as described above) or a class derived
(Clause 10) from its class,
— after the . operator applied to an expression of the type of its
class (5.2.5) or a class derived from its class,
— after the -> operator applied to a pointer to an object of its class
(5.2.5) or a class derived from its class,
— after the :: scope resolution operator (5.1) applied to the name of
its class or a class derived from its class.
Take into account that (9.2 Class members)
1 ...Members of a class are data members, member functions (9.3),
nested types, and enumerators.
Thus in this program
#include <iostream>
struct mystruct
{
enum {INT, FLOAT, STRING} type;
int integer;
float floating_point;
} tu;
/* Why is INT accessible here? */
int main()
{
tu.type = INT; // Invalid access of class member
tu.integer = 100;
return 0;
}
You shall access class member INT in one of the following ways.
tu.type = mystruct::INT;
or
tu.type = tu.INT;
or even like
tu.type = ( &tu )->INT;
The answers given by Vlad and Arachtor are good as far as they go, but there is a question they do not address: why C++ does it differently. If someone is familiar with Stroustrup's book, they may be able to improve this, but I suppose:
C was designed long ago to be fairly easy to compile, while C++ aims to make programming more reliable by using OO, whose main ideal is “in one place, tell the user of a construct all they need to know to use it and no more”; this has the often unspoken benefit of bringing together what belongs together.
This leads to the decisions to use type definitions to limit the scope of some definitions, and to place constructs within a hierarchy of namespaces.
By restricting the scope of a nested enum it is possible to use shorter names without risk of ambiguity or clashes.

Initializing fields of a structure

I'm working on a hash table assignment and I'm getting an unexpected error when trying to initialize my structure variables with a macro value. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "symTable.h"
#define DEFAULT_TABLE_SIZE 61
#define HASH_MULTIPLIER 65599
typedef struct Node
{
char *key;
int *value;
struct Node *next;
} Node_T;
typedef struct SymTable
{
Node_T **Table;
int tablesize = DEFAULT_TABLE_SIZE; //where I am getting my error
int counter = 1;
} *SymTable_T;
and the error I am getting is
error: expected ':', ',', ';', '}' or '__attribute__' before '=' token
Can someone explain to me why it isn't accepting my macro value?
You try to initialize a member in a struct definition, which is a type1. That's no variable definition and doesn't take up any memory at runtime, mind you. You don't define any variable at all, so there's nothing to initialize.
When actually defining a variable you can do something similar by using a designated initializer list:
struct SymTable table = { .tablesize = DEFAULT_TABLE_SIZE, .counter = 1 };
This feature is only available since C99, however (GCC implements it as a non-conformant extension since C90!). Another, < C99 way, would be the somewhat bulkier
struct SymTable table = { NULL, DEFAULT_TABLE_SIZE, 1 };
where you need to know the order of members and the default values of each member.
1 Thanks to #M.M for that neat wording!
You are trying to use an assignment in the definition of struct SymTable. This is a structure, i.e. a kind of type. You can't assign a value to a type, or to a part of a type: a type isn't a piece of storage, it's a classification of storage.
You can use an assignment when defining an object of type struct SymTable. You can assign all the fields; if you omit some fields, the fields you omit will be initialized to “zero” (meaning 0 for integer fields, 0.0 for floating point fields, NULL for pointer fields).
struct SymTable syms1 = {NULL, DEFAULT_TABLE_SIZE, 1};
struct SymTable syms2 = {.counter = 1, .tablesize = DEFAULT_TABLE_SIZE};
The syntax I used for syms2 was introduced in C99, which is supported by most but not all common compilers). The syntax I used for syms1 has existed since the dawn of time; it has the downside that you need to provide values for the fields in order.
If you were trying to provide default values for any new object of type struct symTable, this is not a feature that C provides natively. A struct symTable declared by just writing struct symTable somename; in a function has uninitialized content, and there's nothing you can do about it. You can do it via a macro, but you'll need to call the macro explicitly when you create an object.
#define STRUCT_SYMTABLE_DEFAULT {NULL, DEFAULT_TABLE_SIZE, 1}
…
struct symTable syms3 = STRUCT_SYMTABLE_DEFAULT;
This approach has some downsides: you can only use this to initialize a struct, you can't use this syntax to assign a value later. Also, there's no type checking. A way to fix these defects is to return a value from a function. Good compilers will optimize it to the same code.
struct symTable inline symTable_default(void) {
struct symTable default = {NULL, DEFAULT_TABLE_SIZE, 1};
return default;
}
…
struct symTable syms4 = symTable_default();
…
/* Reset the table to its default value */
syms4 = symTable_default();

About default C struct values, what about this code?

I'm trying to create structs with default values. I don't know how to accomplish this because every code that I see, is about initialising, and I would it for the natural way like...
struct stuff {
int stuff_a = 1;
int stuff_b = 2...
...and so on...
};
and looking about, I found this (C++) code:
struct a{ a() : i(0), j(0) {}; INT i; INT j;}
I never saw anything like this for C. Please, help me to understand it; I think that it is very nice!
UPDATE: Wait, I'm asking about C!!!! Why changed my question? If that is not possible in C just say... I don't know C++, I didn't know that was about C++...
If you want to set a struct object in one go and you have a C99 compiler, try this:
struct stuff {
int stuff_a;
int stuff_b;
// and so on...
};
struct stuff foo;
/* ... code ... */
foo = (struct stuff){.stuff_b = 42, .stuff_a = -1000};
Otherwise, with a C89 compiler, you have to set each member one by one:
foo.stuff_b = 42;
foo.stuff_a = -1000;
Running example # ideone : http://ideone.com/1QqCB
The original line
struct a{ a() : i(0), j(0) {} INT i; INT j;}
is a syntax error in C.
As you have probably learned from the other answers, in C you can't declare a structure and initialize it's members at the same time. These are different tasks and must be done separately.
There are a few options for initializing member variables of a struct. I'll show a couple of ways below. Right now, let's assume the following struct is defined in the beginning of the file:
struct stuff {
int stuff_a;
int stuff_b;
};
Then on your main() code, imagine that you want to declare a new variable of this type:
struct stuff custom_var;
This is the moment where you must initialize the structure. Seriously, I mean you really really must! Even if you don't want to assign specific values to them, you must at least initialize them to zero. This is mandatory because the OS doesn't guarantee that it will give you a clean memory space to run your application on. Therefore, always initialize your variables to some value (usually 0), including the other default types, such as char, int, float, double, etc...
One way to initialize our struct to zero is through memset():
memset(&custom_var, 0, sizeof(struct stuff));
Another is accessing each member individually:
custom_var.stuff_a = 0;
custom_var.stuff_b = 0;
A third option, which might confuse beginners is when they see the initialization of struct members being done at the moment of the declaration:
struct stuff custom_var = { 1, 2 };
The code above is equivalent to:
struct stuff custom_var;
custom_var.stuff_a = 1;
custom_var.stuff_b = 2;
... create structs with default values ...
That is impossible in C. A type cannot have default values. Objects of any type cannot have a default value other than 0, though they can be initialized to whatever is wanted.
The definition of a struct is a definition of a type, not of an object.
What you asking is about the same thing as a way to have ints default to, say, 42.
/* WRONG CODE -- THIS DOES NOT WORK */
typedef int int42 = 42;
int42 a;
printf("%d\n", a); /* print 42 */
Or, adapting to your example
/* WRONG CODE -- THIS DOES NOT WORK */
struct stuff {
int42 stuff_a;
int65536 stuff_b;
}
struct stuff a;
printf("%d\n", a.stuff_b); /* print 65536 */
Update: This answer assumes we 're talking about C++ because the code posted in the answer is not legal C.
struct a {
a() : i(0), j(0) {} // constructor with initialization list
int i;
int j;
}
The line marked with the comment is simply the constructor for instances of struct a (reminder: structs are just like classes, except that the default member visibility is public instead of private).
The part after the : is called an initialization list: it allows you to initialize the members of the struct with values (either constants or passed as constructor parameters). Initialization of members in this list happens before the body of the constructor is entered. It is preferable to initialize members of classes and structs this way, if at all possible.
See also C++: Constructor versus initializer list in struct/class.
in C (pre C99) the following also works:
#include <stdio.h>
typedef struct
{
int a;
int b;
int c;
} HELLO;
int main()
{
HELLO a = {1,2,3};
printf("here: %d %d %d\n",a.a,a.b,a.c);
exit(1);
}
See codepad
I'm not sure quite sure what your problem is. The standard way of initialising structures in c is like this:
struct a_struct my_struct = {1, 2};
Or the more recent and safer:
struct a_struct my_struct = {.i1 = 1, .i2 = 2};
If there is more than one instance of a structure, or it needs to be re-initialised, it is useful to define a constant structure with default values then assign that.
typedef struct a_struct {
int i1;
int i2;
} sa;
static const sa default_sa = {.i1 = 1, .i2 = 2};
static sa sa1 = default_sa;
static sa sa2 = default_sa;
// obviously you can do it dynamically as well
void use_temp_sa(void)
{
sa temp_sa = default_sa;
temp_sa.i2 = 3;
do_something_with(&temp_sa);
}
// And re-initialise
void reset_sa(sa *my_sa)
{
*my_sa = default_sa;
}
Type initializer is not possible in C.
A value must be stored in the memory.
A type does not occupy memory, what occupies memory is a variable of that type.
struct stuff; is a type; it does not occupy memory
struct stuff aStuff; is a variable of that type; aStuff occupies memory
Because a type does not occupy memory, it is not possible to save values into a type.
If there is syntactic sugar to support store/initialize values into a type then there must be additional code that is inserted to assign values to every instant variables of that type (e.g: in constructor in C++). This will result in a less efficient C if this feature is available.
How often do you need to retain this default values? I think it is unlikely. You can create a function to initialize variable with the default values or just initialize every fields with the values you want. So type initializer is not fundamental thing. C is about simplicity.
Can't initialize values within a structure definition.
I'd suggest:
typedef struct {
int stuff_a;
int stuff_b;
} stuff ;
int stuffInit(int a, int b, stuff *this){
this->stuff_a = a;
this->stuff_b = b;
return 0; /*or an error code, or sometimes '*this', per taste.*/
}
int main(void){
stuff myStuff;
stuffInit(1, 2, &myStuff);
/* dynamic is more commonly seen */
stuff *dynamicStuff;
dynamicStuff = malloc(sizeof(stuff)); /* 'new' stuff */
stuffInit(0, 0, dynamicStuff);
free(dynamicStuff); /* 'delete' stuff */
return 0;
}
Before the days of Object Oriented Programming (C++), we were taught "Abstract Data Types".
The discipline said 'never access your data structures directly, always create a function for it' But this was only enforced by the programmer, instructor, or senior developer, not the language.
Eventually, the structure definition(s) and corresponding functions end up in their own file & header, linked in later, further encapsulating the design.
But those days are gone and replaced with 'Class' and 'Constructor' OOP terminology.
"It's all the same, only the names have changed" - Bon Jovi.

Resources