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.
Related
How do I call a function that takes an anonymous struct in C?
Such as this function
void func(struct { int x; } p)
{
printf("%i\n", p.x);
}
When a function declaration that provides a prototype is in scope, the arguments to calls to that function must be have types compatible with those declared in the prototype, where "compatible" has a specific meaning defined by the standard:
Two types have compatible type if their types are the same. Additional
rules for determining whether two types are compatible are [not relevant to the case in question]. Moreover, two structure, union, or enumerated types declared in separate translation units are compatible
if their tags and members satisfy the following requirements: If one
is declared with a tag, the other shall be declared with the same tag.
If both are completed anywhere within their respective translation
units, then the following additional requirements apply: there shall
be a one-to-one correspondence between their members such that each
pair of corresponding members are declared with compatible types; [...] and if one
member of the pair is declared with a name, the other is declared with
the same name. For two structures, corresponding members shall be
declared in the same order. [...]
(C11, 6.2.7/1)
Being "the same type" in the sense meant by the standard is a matter of scope, and there is no way for a caller of your function to satisfy that because the scope of the structure declaration in a function parameter list is restricted to the function definition in which it appears, if any, or to the parameter list alone if it appears only in a prototype.
To call that function, then, you must somehow take advantage of the additional rules for type compatibility, which are applicable (only) if func() is defined in a different translation unit than the caller. In that case, the easiest thing to do is probably to typdef a compatible type in the caller's translation unit:
typedef struct { int i; } one_int;
You would then prototype the function like so in that TU:
void func(one_int p);
and you would call it with a parameter of type one_int. For example,
one_int oi = { 1 };
func(oi);
Do note, however, that although the above prototype is compatible with the function definition given in the question as long as they appear in different translation units, the two cannot appear in the same translation unit, so you cannot follow the usual recommendation that each .c file #include the header(s) declaring its functions.
Overall, it would be far better to lift the struct declaration out of the prototype, either with the help of a typedef such as is demonstrated above, or by giving it a tag, either one of which provides for it to be referenced from code away from its definition.
Although useful for some applications, a bare naked anonymous struct cannot be passed as a function argument all by itself in C. It needs some help, eg either a typedef handle, or a as a member of a named struct.
anonymous struct by itself:
struct {
int x;
};
as a function argument results in the warning:
"expected ‘struct ’ but argument is of type ‘struct ’ void func(struct { int x; } p)"
(noted by #Eugene Sh)
Help with a Typedef:
typedef struct
{
int x;
}anon_s;
void func(anon_s *p)
{
printf("%i\n", p->x);
}
int main(void)
{
anon_s anon = {10};
func(&anon);
return 0;
}
Or, carried by a surrogate with either a name or typedefed:
struct anon{
// Anonymous struct
struct
{
int x;
};
};
As type of the anonymous struct is visible only within the body of func() you could use it to call func() recursively.
void func(struct { int x; } p)
{
printf("x=%d\n", p.x);
func(p);
}
The code compiles fine except a warning mentioned in other answers.
Thus it is theoretically possible to call a function with anonymous struct as parameter. The initial call is a challange. I do not think that that there any portable way of invoking an initial call. Probably doable by casting a pointer func() to other type of function pointer that is binary-compatible for a given implementation.
void func(struct { int x; } p)
{
printf("x=%d\n", p.x);
if (p.x --> 0)
func(p);
}
int main() {
// call through a pointer to function with unspecified number of arguments.
void (*func_p)() = func;
struct almost_p { int x; } p = { 10 };
func_p(p);
return 0;
}
Ii worked perfectly on my machine but it's non-portable and likely could trigger UB due incompatibility of struct {...} and struct almost_p.
However, if the argument is a pointer to anonymous struct then the situation looks more promising.
void func(struct { int x; } *p);
One can make an initial call as func(NULL).
Within func, the actual p object can be constructed with calloc().
After that you can call it func() recursively or store instance p in a global variable of type void*.
Example:
void func(struct { int x; } *p) {
if (!p) p = calloc(1, sizeof *p);
printf("x=%d\n", p->x);
if (p->x++ < 10)
func(p);
}
int main() {
func(NULL);
return 0;
}
It compiles fine and outputs:
x=0
x=1
x=2
x=3
x=4
x=5
x=6
x=7
x=8
x=9
x=10
If you compile your program with warnings enabled you will get a warning like
warning: anonymous struct declared inside parameter list will not be visible outside of this definition or declaration
void func(struct { int x; } p)
^~~~~~
Therefor you need to give the record a name and use this name in the function declaration, for instance
typedef struct {
int x;
} T;
void func(T p)
{
printf("%i\n", p.x);
}
For starters you have no anonymous structure. You have an unnamed structure. The notion anonymous structure has a specific semantic in C.
You can not call the function because the structure type even if it will be named is not visible outside the function block scope.
You need to declare the structure outside the function parameter list assigning to it a name or an alias using typedef.
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;
}
Is there an order of lookup in the namespaces namely, tag namespace and ordinary name space ? Consider the following code :
#include <stdio.h>
int main (void){
typedef struct{ //This belongs to ordinary name space
int min;
} st;
st myst;
myst.min=6;
struct myst{ // This belongs to tag name space
int min;
};
myst.min=7;
printf("%d\n%d\n",myst.min,myst.min);
return 0;
}
Output
7
7
The compiler looks for the variable to print in the tag namespace first , I guess. I don't know if the lookup is even done for the same identifier in the ordinary namespace and if it is done I am clueless why it doesn't print it.
There is no namespace lookup order in C. Only one namespace is ever considered for any particular identifier; it is determined by what kind of identifier is being looked up. Structure tags are one kind, with their own namespace; variable names are in the broader category of "ordinary identifiers", which have a separate namespace. There are other name spaces, too, but the compiler can always tell from context which one is relevant to any given identifier.
Thus, in your program, both uses of myst.min refer to the variable declared as st myst; and there isn't any second variable in the "tag" namespace (as you seem to have thought there would be).
You can see this for yourself by commenting out everything within main above myst.min = 7:
#include <stdio.h>
int main (void){
#if 0
typedef struct{ //This belongs to ordinary name space
int min;
} st;
st myst;
myst.min=6;
#endif
struct myst{ // This belongs to tag name space
int min;
};
myst.min=7;
printf("%d\n%d\n",myst.min,myst.min);
return 0;
}
Attempting to compile this will produce a hard error:
test.c: In function ‘main’:
test.c:14:3: error: ‘myst’ undeclared (first use in this function)
What the struct myst declaration does is declare another type, which you can then use to declare variables. But it's not used for anything unless you actually do that. For instance
#include <stdio.h>
typedef struct { int min; } st;
struct myst { int min };
int main(void)
{
// uses the typedef name 'st', in the ordinary namespace,
// to declare the variable 'myst', also in the ordinary namespace
st myst = { 6 };
// uses the struct name 'myst', in the tag namespace,
// to declare the variable 'myst2', in the ordinary namespace
struct myst myst2 = { 7 };
printf("%d %d\n", myst.min, myst2.min);
return 0;
}
will print 6 7. This program also illustrates how myst, the variable, and myst, the struct tag, are indeed in two different namespaces and can be referred to independently.
(Thanks to John Bollinger for the new first paragraph. —ed)
C namespaces are completely disjoint. Each identifier is searches ony in one namespace. For example:
Identifiers that follow structand union keywords are searched in the tag namespace
Identifiers that follow the goto keyword are searched in the label namespace
Identifiers that follow . or -> symbols are searched in their structure or union member namespace (each structure and union has its own member namespace; type of the preceding expression determines which one to search)
Other identifiers are searched in the ordinary namespace.
There is no lookup order. The (unique) namespace to search is completely determined by the context.
Trying some code, I realized that the following code compiles:
struct { int x, y; } foo(void) {
}
It seems as if we are defining a function named foo which returns an anonymous struct.
Does it only happen to compile with my compiler or is this legal C(99)?
If so, what is the correct syntax for a return statement and how can I correctly assign the returned value to a variable?
The struct you're returning is not an anonymous struct. The C standard defines an anonymous struct as a member of another struct that doesn't use a tag. What you're returning is a struct without a tag, but since it isn't a member, it is not anonymous. GCC uses the name < anonymous > to indicate a struct without a tag.
Let's say you try to declare an identical struct in the function.
struct { int x, y; } foo( void )
{
return ( struct { int x, y; } ){ 0 } ;
}
GCC complains about it: incompatible types when returning type 'struct < anonymous>', but 'struct <anonymous>' was expected.
Apparently the types are not compatible. Looking in the standard we see that:
6.2.7 Compatible type and composite type
1: Two types have compatible type if their types are the same. Additional rules for determining whether two types are compatible are described in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers, and in 6.7.6 for declarators. Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. If both are completed anywhere within their respective translation units, then the following additional requirements apply: there shall be a one-to-one correspondence between their members such that each pair of corresponding members are declared with compatible types; if one member of the pair is declared with an alignment specifier, the other is declared with an equivalent alignment specifier; and if one member of the pair is declared with a name, the other is declared with the same name. For two structures, corresponding members shall be declared in the same order. For two structures or unions, corresponding bit-fields shall have the same widths. For two enumerations, corresponding members shall have the same values.
The second bold part, explains that if both struct are without the tag, such as in this example, they have to follow additional requirements listed following that part, which they do. But if you notice the first bold part, they have to be in separate translation units, and structs in the example aren't. So they are not compatible and the code is not valid.
It is impossible to make the code correct since if you declare a struct and use it in this function. You have to use a tag, which violates the rule that both have structs have to have the same tag:
struct t { int x, y; } ;
struct { int x, y; } foo( void )
{
struct t var = { 0 } ;
return var ;
}
Again GCC complains: incompatible types when returning type 'struct t' but 'struct <anonymous>' was expected
This works in my version of GCC, but seems like a total hack. It is perhaps useful in auto-generated code where you don't want to deal with the additional complexity of generating unique structure tags, but I'm sort of stretching to come up with even that rationalization.
struct { int x,y; }
foo(void) {
typeof(foo()) ret;
ret.x = 1;
ret.y = 10;
return ret;
}
main()
{
typeof(foo()) A;
A = foo();
printf("%d %d\n", A.x, A.y);
}
Also, it's dependent on typeof() being present in the compiler -- GCC and LLVM seem to support it, but I'm sure many compilers do not.
You probably cannot explicitly return some aggregate value from your function (unless you use a typeof extension to get the type of the result).
The moral of the story is that even if you can declare a function returning an anonymous struct, you should practically never do that.
Instead, name the struct and code:
struct twoints_st { int x; int y; };
struct twoints_st foo (void) {
return ((struct twoints_st) {2, 3});
};
Notice that it is syntactically ok, but it is generally undefined behavior at execution to have a function without return (e.g., you could call exit inside it). But why would you want to code the following (probably legal)?
struct { int xx; int yy; } bizarrefoo(void) { exit(EXIT_FAILURE); }
Here's a way to return anonymous structs in C++14 without any hacks I just discovered.
(C++ 11 should be sufficient, I suppose)
In my case a function intersect() returns std::pair<bool, Point> which is not very descriptive so I decided to make a custom type for the result.
I could have made a separate struct but it wasn't worth since I would need it only for this special case; that's why I used an anonymous struct.
auto intersect(...params...) {
struct
{
Point point;
bool intersects = false;
} result;
// do stuff...
return result;
}
And now, instead of the ugly
if (intersection_result.first) {
Point p = intersection_result.second
I can use the much better looking:
if (intersection_result.intersects) {
Point p = intersection_result.point;
You could define a structure in specification of the return argument. Moreover you can use compound literals introduced in C99 for brevity:
#include<stdio.h>
struct foo { int x, y; }
foo( void )
{
return (struct foo){ 1, 2 } ;
}
int main()
{
struct foo res = foo();
printf("%d %d\n", res.x, res.y);
}
prints:
1 2
The code compiles in pedantic mode for C99 with no warnings. Note that the tag name is the same as function. This works because namespaces for structs and global objects are separated. This way you minimize the chances for accidental conflict of names. You can use something like foo_result if you consider it more suitable.
Or you could create infinite recursion:
struct { int x, y; } foo(void) {
return foo();
}
Which I think is completely legal.
This works up to the newest version of GCC. It is particularly useful for creating dynamic arrays with macros. For instance:
#define ARRAY_DECL(name, type) struct { int count; type *array; } name
Then you can make the array with realloc, etc. This is useful because then you can create a dynamic array with any type, and there is one way to make all of them. Otherwise, you would end up using a lot of void *'s and then writing functions to actually get the values back out with casts and such. You can shortcut all of this with macros; that is their beauty.
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.