Creating "nested structs" without -fms-extensions? - c

I have a struct with some properties:
struct a {
char* id;
int a;
int b;
int c;
}
I also have a struct with the same properties, but without the id.
struct b {
int a;
int b;
int c;
}
I know that C11 supports anonymous structs, so I could do something like this:
struct a {
char* id;
struct {
int a;
int b;
int c;
}
}
However, if I give the inner struct a tag, it fails. Is it possible to create nested structs like this without using a non-standard compiler option like -fms-extensions?

You can give the inner structure a name or a tag or both in C11 (i.e., without the use of any extension).
Without a tag and without a name, your inner structure is a C11 anonymous structure:
struct a {
char* id;
struct {
int a;
int b;
int c;
};
};
If you give the inner anonymous structure a name, it is no longer an anonymous structure. It is a regular C89/C99/C11 structure member and you cannot access the inner structure members directly as with anonymous structures.
If you give the inner anonymous structure a tag (but still no name), it is just a C89/C99/C11 structure declaration. There is no member added and the declaration of struct a is the same as:
struct a {
char* id;
};

Related

struct Employee {} compare struct {} Employee

I read a tutorial in which there is this struct:
struct
{
char Name[25];
int Age;
float SkillRating;
} Employee;
defines a new aggregate, called Employee, containing fields called Name (of type character), Age (of type integer), and SkillRating (of type float).
In contrast, the C statement:
struct EmployeeType
{
char Name[25];
int Age;
float SkillRating;
};
does not define a new aggregate variable, but defines a new aggregate type,
EmployeeType.
This new data type could then be used to declare variables in the
same way as a primitive data type. That is, in the same way that C allows the
variable x to be declared as an integer using the statement
I am confused here. Does the distinction exist if place 'Emplyee` on different position?
I guess they are identical.
In the first case, the struct is unnamed and Employee is a variable of that unnamed struct. You can directly modify it like this:
int main()
{
Employee.Age = 100;
return 0;
}
In the second case, EmployeeType is just a type, but you didn't make any instance of it yet. You can make any amount of instances:
int main()
{
struct EmployeeType a; // employee on the stack
a.Age = 100;
struct EmployeeType *b = malloc(sizeof(struct EmployeeType)); // employee on the heap
if (b) { // set the age of b if the allocation succeeded
b->Age = 100;
}
free(b); // malloc-allocated memory must be freed afterwards
return 0;
}
You can even do both at once:
struct EmployeeType
{
char Name[25];
int
Age;
float SkillRating;
} Employee;
Here, Employee is one instance of it, but you can make additional instances:
int main()
{
Employee.Age = 100;
struct EmployeeType a; // employee on the stack
a.Age = 100;
return 0;
}
struct A_s { int memb; }; // declares a struct A_s
struct A_s a; // declares a variable a of type struct A_s
now you can combine struct declaration with variable declaration:
// declares struct A_s and in the same line declares variable a
struct A_s { int memb; } a;
Now you can create an anonymous struct by omitting the structure tag name:
// declares anonymous struct and in the same line declares variable a
struct { int memb; } a;
Now structure declaration can be really put anywhere:
int func(int a, struct A_s { int memb; } b);
struct A_s { int memb; } func(int a);
struct B_s {
int memb1;
struct A_s {
int memb2;
} a;
};
I think the description of the C code of the field "name" in your post is invalid. The field name inside "aggregate" (read as: structure) has the type "array of 25 characters", not character type.
struct keyword in C can be used to declare aggregate datatypes, aggregate data objects or both.
In your first declaration (and definition), a tag name is missing, so an anonymous object 'Employee' is created. 'Employee' remains the only object of this struct. You cannot create more objects from this struct anywhere else in the code.
In your second declaration, you have created a struct type which can be instantiated many times (i.e., multiple instances of this struct can exist) as shown below -
struct EmployeeType employee_1;
struct EmployeeType employee_2;
Both these syntax are useful depending on the use case.

Access struct field within another struct without referring to inner struct

Suppose I have a struct that is defined as the following:
struct entity {
int x;
int y;
};
And a struct that uses it as a member:
struct player {
struct entity position;
char* name;
};
If I write the following code then I get an error:
struct player p;
p.x = 0; //error: 'struct player' has no member named 'x'
What I have been doing so far is writing a function that takes a player struct and returns the value by doing return player.position.x.
Is there a compiler flag, or other method, that allows me to "flatten" (I'm not sure if that's the correct phrase) the struct and allows me to access the x variable like I have shown above? I realize that this might be ambiguous if there is also an integer named x inside player as well as in entity.
Please note I will be using the entity struct in multiple structs and so I cannot use a anonymous struct inside player.
Put succinctly, the answer is "No". This is especially true if you've looked at questions such as What are anonymous structs and unions useful for in C11 and found them not to be the solution.
You can look at C11 §6.7.2.1 Structure and union specifiers for more information about structure and union types in general (and ¶13 specifically for more information about anonymous members, and ¶19 for an example). I agree that they are not what you're after; they involve a newly defined type with no tag and no 'declarator list'.
Using a macro, we can make a type generator:
#define struct_entity(...) \
struct __VA_ARGS__ { \
int a; \
int b; \
}
Then we can instantiate that type as either a tagged or anonymous structure, at will:
struct_entity(entity);
struct player {
struct_entity();
const char *name;
};
int main() {
struct player player;
player.a = 1;
player.b = 2;
player.name = "bar";
}
This code is closer in intent to what you want, and doesn't have the UB problem of the approach of declaring just the structure members in the macro. Specifically, there is a structure member inside of struct player, instead of individual members. This is important, because padding reduction and reordering of members may be performed by the compiler - especially on embedded targets. E.g. composite_1 and composite_2 below do not necessarily have the same layout!:
#include <assert.h>
#include <stddef.h>
typedef struct sub_1 {
int a;
void *b;
char c;
} sub_1;
typedef struct sub_2 {
void *d;
char e;
} sub_2;
typedef struct composite_1 {
int a;
void *b;
char c;
void *d;
char e;
} composite_1;
typedef struct composite_2 {
struct sub_1 one;
struct sub_2 two;
} composite_2;
// Some of the asserts below may fail on some architectures.
// The compile-time asserts are necessary to ensure that the two layouts are
// compatible.
static_assert(sizeof(composite_1) == sizeof(composite_2), "UB");
static_assert(offsetof(composite_1, a) == offsetof(composite_2, one.a), "UB");
static_assert(offsetof(composite_1, b) == offsetof(composite_2, one.b), "UB");
static_assert(offsetof(composite_1, c) == offsetof(composite_2, one.c), "UB");
static_assert(offsetof(composite_1, d) == offsetof(composite_2, two.d), "UB");
static_assert(offsetof(composite_1, e) == offsetof(composite_2, two.e), "UB");
You can define then as MACROs:
#define ENTITY_MEMBERS int x; int y
struct entity{
ENTITY_MEMBERS;
}
struct player {
ENTITY_MEMBERS;
char* name;
};
Actually this is how you mimic C++ single inheritance in C.

Nested struct in C issue

I have a struct declaration in C that looks something like this:
static struct {
int a;
int b;
} myStruct[10];
I want to declare a struct member variable inside myStruct, so I try to add this:
static struct {
int c;
int d;
struct myStruct[10] s;
} myNestedStruct[100];
I'm getting a bunch of errors i.e. syntax error before or at: [ and
syntax requires ";" after last struct/union member. What would the better way to implement the nested structs be?
EDIT: My code now looks like this:
static struct {
int a;
int b;
} myStruct[10];
static struct {
int c;
int d;
struct myStruct s[10];
} myNestedStruct[100];
However I'm getting an error: incomplete struct/union/enum myStruct: s
You need to declare myStruct first before using it as a struct type.
struct myStruct {
int a;
int b;
};
static struct {
int c;
int d;
struct myStruct s[10];
} myNestedStruct[100];
This creates a variable called myNestedStruct which is an array of 100 structs, each containing two ints and an array of 10 mystructs.
When you write code like
struct { ... } Foo;, it's not declaring a type named Foo but a variable. Its type is an anonymous struct corresponding to what you put in the curly braces. If you want to declare a type, write struct Foo { ... };.
That's where your error is coming from -- myStruct is not a type name, so when you write struct myStruct in the definition of myNestedStruct the compiler thinks you're about to define a struct by that name. But then it encounters an [ which shouldn't be the next token in a struct declaration ever so it tells you can't make sense of the code.

Anonymous struct with ANSI C

I want to know if it is possible to declare anonymous structs in ANSI C. The code I have is:
struct A
{
int x;
};
struct B
{
struct A;
int y;
};
When I compile it I get:
warning: declaration does not declare anything
I have read that the flag -fms-extensions does the trick, it however only works on windows systems as it produces:
warning: anonymous structs are a Microsoft extension [-Wmicrosoft]
Is there any ANSI equivalent extension that I can use?
A trick to get almost this feature in ANSI C is to use an appropriate macro:
struct A {
int x;
};
struct B {
struct A A_;
int y;
};
#define bx A_.x
Then you can simply do
struct B foo, *bar;
foo.bx;
bar->bx;
In C11 though, anonymous structures are supported and you can simply do
struct B {
struct {
int x;
};
int y;
}
but sadly not
struct A {
int x;
};
struct B
{
struct A;
int y;
};
As the anonymous structure has to be declared inside the structure it is anonymous to.
See this answer for more details on anonymous members in C11.
Its possible to declare anonymous struct and union. The ISO C11 added this feature and GCC allows it as an extension.
C11 section §6.7.2.1 para 13:
An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.
19 The following illustrates anonymous structures and unions:
struct v {
union { // anonymous union
struct { int i, j; }; // anonymous structure
struct { long k, l; } w;
};
int m;
} v1;
v1.i = 2; // valid
v1.k = 3; // invalid: inner structure is not anonymous
v1.w.k = 5; // valid
Now b can be accessed by just using foo.b.
You want something like this i suppose:
struct B {
struct {
int x;
} A;
int y;
};
And you could do:
struct B b;
b.A.x = 5;
printf( "%d\n", b.A.x );

How to declare a variable of struct that declared inside another struct?

I have a struct that declared as follow:
struct a {
struct b {
int d;
} c;
};
How to declare a variable of b outside a? In C++ I can use a::b x;. But, in C it required to specifies struct keyword before struct name.
C has a flat layout; when you declare a struct within another struct, the former is just being put into the global namespace.
So, in your example, it is just struct b.
C does not have nested types. You can't write a::x b or anything that ressembles it. If you want to get rid of the struct keyword, that's another problem. Use typedefs. but it won't allow to nest types.
typedef struct b_t {
int d;
} b;
typedef struct {
b c;
} a;
b some_b;
a some_a;
int f() {
some_b.d=42;
some_a.c=some_b;
return 0;
}
.

Resources