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 );
Related
I have the following structure of union and structs
union ab {
struct {
int a;
} a_st;
struct {
int b;
} b_st;
};
typedef struct c {
union ab;
} c_st;
when trying to "reach" the union elements directly:
c_st c;
printf("%d\n", c.a_st.a);
the following compilation error raised:
error: 'c_st' {aka 'struct c'} has no member named 'a_st'
if I provide the union name inside of the 'c_st' struct (e.g. ab_un), it works, but then I need to call c.ab_un.a_st.a, which is less desired.
is it necessary evil or have I missed something here?
Thanks in advance
Per this answer, the solution for gcc is to compile with -fms-extensions.
Here is an example. Tested with Visual C++ and MSYS2 gcc 10.2.
With this version of gcc, the -fms-extensions seems to be implied, and I get an error as mentionned in the comments if I compile instead with -fno-ms-extensions.
#include <stdio.h>
union ab {
struct {
int a;
} a_st;
struct {
int b;
} b_st;
};
typedef struct d {
union ab;
struct {
int c;
} c_st;
} d_st;
int main(void) {
d_st x;
printf("%zu\n", sizeof(d_st));
x.a_st.a = 1;
x.b_st.b = 2;
x.c_st.c = 3;
printf("a_st = %d\n", x.a_st.a);
printf("b_st = %d\n", x.b_st.b);
printf("c_st = %d\n", x.c_st.c);
return 0;
}
As an extension MSVC compiler (see Microsoft Specific Anonymous Structures) and gcc compiler with -fms-extensions (see gcc docs unnamed fields) support the syntax of unnamed structures. When using this extension it allows the code to compiler and access the unnamed structure members as if they were members of the containing structure.
If using this extension, the code will compile and access is fine, you just made a typo c_st should be d_st.
#include <stdio.h>
union ab {
struct {
int a;
} a_st;
struct {
int b;
} b_st;
};
typedef struct d {
union ab;
} d_st;
int main(void) {
d_st c;
printf("%d\n", c.a_st.a);
}
Without using this extension, the code will not compile, as explained below.
is it necessary evil or have I missed something here?
I would say it's just evil. The problem is with the following part:
struct c {
union ab;
};
It's the same as writing:
struct c {
};
You can put any type and follow it with a ;, like:
struct d {
int; float; unsigned long long; FILE *; some_other_type;
};
union ab is just a type. The some_type ; doesn't declare anything, nothing happens. The language grammar just allows you to write just a type as an expression without an identifier (ie. it's used in function declaration like void func(char*, int)), but nothing happens and such expression has no meaning. Your struct c is just empty, it has no members, it's undefined behavior.
trying to "reach" the union elements directly:
You can't access them, because they don't exists. There are no elements inside struct c - it's empty.
You may duplicate code (possibly with a macro):
struct c {
union { // anonymous union
struct {
int a;
} a_st;
struct {
int b;
} b_st;
};
};
and access via:
struct c C;
printf("%d\n", C.a_st.a);
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I would like to know why and when one would explicitly choose to use an anonymous structure like so:
typedef struct my_struct_t my_struct_t;
struct my_struct_t
{
int a;
int b;
};
int main()
{
my_struct_t obj1 =
{
.a = 33,
.b = 44
};
return 0;
}
rather than doing:
typedef struct my_struct_t my_struct_t;
struct my_struct_t
{
int a;
int b;
};
int main()
{
my_struct_t obj2;
obj2.a = 55;
obj2.b = 66;
return 0;
}
What advantages does the former offer over the latter and/or vice-verca?
thanks
An anonymous struct is useful when you want to nest structures/unions without assigning a particular "meaning" to the inner structures. It lets you access the members of an inner structure as if they were a direct member of the enclosing struct. See the following example taken from cppreference.com:
Similar to union, an unnamed member of a struct whose type is a struct
without name is known as anonymous struct. Every member of an
anonymous struct is considered to be a member of the enclosing struct
or union. This applies recursively if the enclosing struct or union is
also anonymous.
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
The code you showed actually has nothing to do with anonymous structs. It is rather an example of using an initializer list with designated members.
Hope it helps :-)
Here's one use. When working with unions, it's implementation defined what you'll get when reading a union member that wasn't last written to. But, in the case of structures, you can inspect the common initial sequence of fields. Here's an example to illustrate:
#include <assert.h>
struct S1 {
int type;
char value;
};
struct S2 {
int type;
float value;
};
union U {
struct S1 s1;
struct S2 s2;
};
int main() {
union U un;
un.s1.type = 1;
un.s1.value = 'c';
assert(un.s2.type == 1);
}
As you can see above, it is guaranteed by the C standard that whatever I write to un.s1.type I can then read from un.s2.type. So far so good. But there's a problem if I try to do something like this instead:
union U {
struct S1 s1;
int type;
};
Now there is no guarantee. We can't read un.s1.type from un.type under the protection of the standard. But hope is not lost, we can just make it a field of a structure again, an anonymous structure, like so:
union U {
struct S1 s1;
struct {
int type;
};
};
The fields of an anonymous structure are "injected" into the enclosing structure or union, so we may refer to type by accessing un.type. And now were are back to the warm embrace of the standard. Since now we again have two structures with a common initial sequence of fields.
Your example has nothing to do with anonymous structs, but only with initialization vs. assignement. It matters mainly when objects are declared const:
const my_struct_t obj1 =
{
.a = 33,
.b = 44
};
is correct while this is not:
const my_struct_t obj2;
obj2.a = 55; // error: try to assign to const object
Anonymous structures and unions allow members of a sub struct/union to be used as if they were members of the containing sub/union.
Draft n1570 for C11 says at 6.7.2.1 Structure and union specifiers §13 says:
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.
and even gives a (non normative) example:
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
That's not an anonymous struct, that is simply using designated initializers, and you use them particularly when you don't need to provide values for all the members of a complicated struct.
If I have these structures:
typedef struct { int x; } foo;
typedef struct { foo f; } bar;
Normally you would access x through b.f.x, but is there a way to set this up so that you can access element x without referring to f?
bar b;
b.x = ...
My first intuition is that you can't since there would be a possibility for name conflicts if two sub structures both had a member x and I can't figure out what the compile error would be. However, I recall working in some frameworks where this was possible.
In C++ I worked in a framework once where bar existed, and you could access its members as member variables this->x from a different class. I'm trying to figure out how that could be done.
You can with C11:
§ 6.7.2.1 -- 11
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.
So this code might work:
#include <stdio.h>
typedef struct { int x; } foo;
typedef struct { foo; } bar;
int main(void)
{
bar b;
b.x = 1;
printf("%d\n", b.x);
}
The problem here is that different compilers disagree in my tests on whether a typedef is acceptable as a struct specifier with no tag The standard specifies:
§ 6.7.8 -- 3
In a declaration whose storage-class specifier is typedef, each declarator defines an
identifier to be a typedef name that denotes the type specified for the identifier in the way
described in 6.7.6. [...] A typedef declaration does not introduce a new type, only a
synonym for the type so specified.
(emphasis mine) -- But does synonym also mean a typdef-name specifier is exchangeable for a struct specifier? gcc accepts this, clang doesn't.
Of course, there's no way to express the whole member of type foo with these declarations, you sacrifice your named member f.
Concerning your doubt about name collisions, this is what gcc has to say when you put another int x inside bar:
structinherit.c:4:27: error: duplicate member 'x'
typedef struct { foo; int x; } bar;
^
To avoid ambiguity, you can just repeat the struct, possibly #defined as a macro, but of course, this looks a bit ugly:
#include <stdio.h>
typedef struct { int x; } foo;
typedef struct { struct { int x; }; } bar;
int main(void)
{
bar b;
b.x = 1;
printf("%d\n", b.x);
}
But any conforming compiler should accept this code, so stick to this version.
<opinion>This is a pity, I like the syntax accepted by gcc much better, but as the wording of the standard doesn't make it explicit to allow this, the only safe bet is to assume it's forbidden, so clang is not to blame here...</opinion>
If you want to refer to x by either b.x or b.f.x, you can use an additional anonymous union like this:
#include <stdio.h>
typedef struct { int x; } foo;
typedef struct {
union { struct { int x; }; foo f; };
} bar;
int main(void)
{
bar b;
b.f.x = 2;
b.x = 1;
printf("%d\n", b.f.x); // <-- guaranteed to print 1
}
This will not cause aliasing issues because of
§ 6.5.2.3 -- 6
One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members
C: Highly unrecommended, but doable:
#include <stdio.h>
#define BAR_STRUCT struct { int x; }
typedef BAR_STRUCT bar;
typedef struct {
union {
bar b;
BAR_STRUCT;
};
} foo;
int main() {
foo f;
f.x = 989898;
printf("%d %d", f.b.x, f.x);
return 0;
}
Anonymous structs are a widly-spread extension in standards before C11.
C++:
The same as in C, you can do here but anonymous structs are not part of any C++ standard, but an extension.
Better use inheritance, or do not use this shortcut at all.
Of course, do not use something like #define x b.x)).
In C you can't access members of members like this.
You can however access members of an anonymous inner struct:
struct bar {
struct {
int x;
}
};
...
struct bar b;
b.x = 1;
In C++ you use inheritance:
struct foo {
int x;
};
struct bar: public foo {
};
...
struct bar b;
b.x = 1;
In C (99 and onward) you can access the common initial sub-sequence of union members, even if they weren't the last member written to1.
In C11, you can have anonymous union members. So:
typedef struct { int x; } foo;
typedef struct {
union {
foo f;
int x;
};
} bar;
Yes, that applies to structures. But according to the standard:
A structure pointer, suitably converted, points to the first member.
A union pointer, suitably converted, points to any union member.
So their location in memory is the same.
This is not possible in C. In C++ however you can use inheritance which is probably what you were thinking about.
In C++, you can use inheritance and member name conflicts are sort of resolvable with :: and treating the base classes as members.
struct foo { int x; };
struct bar : foo { };
struct foo1 { int x; };
struct bar1 : foo1 { char const* x; };
bar b;
bar1 b1;
int main()
{
return b.x + b1.foo1::x;
}
In standard C, it's impossible, however several compilers (gcc, clang, tinycc) support a similar thing as an extension (usually accessible with -fms-extensions (on gcc also with -fplan9-extensions which is a superset of -fms-extensions)), which allows you to do:
struct foo { int x; };
struct bar { struct foo; };
struct bar b = { 42 };
int main()
{
return b.x;
}
However, there's no resolution for conflicting member names with it, AFAIK.
In C++, it is possible in two ways. The first is to use inheritence. The second is for bar to contain a reference member named x (int &x), and constructors that initialise x to refer to f.x.
In C, it is not possible.
Since the C standard guarantees that there isn't padding before the first member of a struct, there isn't padding before the foo in bar, and there isn't padding before the x in foo. So, a raw memory access to the start of bar will access bar::foo::x.
You could do something like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct _foo
{
int x;
} foo;
typedef struct _bar
{
foo f;
} bar;
int main()
{
bar b;
int val = 10;
// Setting the value:
memcpy(&b, &val, sizeof(int));
printf("%d\n", b.f.x);
b.f.x = 100;
// Reading the value:
memcpy(&val, &b, sizeof(int));
printf("%d\n", val);
return 0;
}
As others have noted, C++ offers a more elegant way of doing this through inheritance.
If I have these two structs:
struct
{
int x;
} A;
struct
{
int x;
} B;
then making A = B; results in a compilation error because the two anonymous structs are not compatible.
However if I do:
typedef struct
{
int x;
} S;
S A;
S B;
A = B; is a legal assignment because they are compatible.
But why? With typedef I understand that the compiler makes this when meet S A and S B:
struct { int x; } A;
struct { int x; } B;
so A and B should not be compatible...
Each anonymous struct declaration is a distinct type; this is why you get a type mismatch when trying to assign one to the other.
A typedef, however, declares an alias (i.e. a new name for something that already exists) for a type (it does not create a new type).
A typedef is also not a simple text replacement, like a preprocessor macro. Your statement
I understand that the compiler make this when meet S A and S B:
struct { int x; } A;
struct { int x; } B;
is where your understanding is wrong.
When you use the type alias S, as in
S A;
S B;
the types of both objects A and B are the same by definition and assigning one to the other is possible.
This is because C treats every untagged struct as a new kind of struct, regardless of the memory layout. However, typedef struct { } name; cannot be used if you want to use the struct in a linked list. You'll need to stick with defining a structure tag in this case, and typedef the tagged struct instead.
struct DistanceInMeter /* Anonymous 1 */
{
int x; /* distance */
};
struct VolumeInCC /* Anonymous 2 */
{
int x; /* volume */
};
struct DistanceInMeter A;
struct VolumeInCC B;
...
A = B; /* Something is wrong here */
Equating different type doesn't always make sense and thus is not allowed.
typedef struct DistanceInMeter /* Anonymous 1 */
{
int x; /* distance */
} Dist_t;
Dist_t C, D;
...
C = D; /* Alright, makes sense */
here is very simplified code of problem I have:
enum node_type {
t_int, t_double
};
struct int_node {
int value;
};
struct double_node {
double value;
};
struct node {
enum node_type type;
union {
struct int_node int_n;
struct double_node double_n;
};
};
int main(void) {
struct int_node i;
i.value = 10;
struct node n;
n.type = t_int;
n.int_n = i;
return 0;
}
And what I don't undestand is this:
$ cc us.c
$ cc -std=c99 us.c
us.c:18:4: warning: declaration does not declare anything
us.c: In function ‘main’:
us.c:26:4: error: ‘struct node’ has no member named ‘int_n’
Using GCC without -std option compiles code above without any problems (and the similar code is working pretty well), but it seems that c99 does not permit this technique. Why is it so and is it possible to make is c99 (or c89, c90) compatible? Thanks.
Anonymous unions are a GNU extension, not part of any standard version of the C language. You can use -std=gnu99 or something like that for c99+GNU extensions, but it's best to write proper C and not rely on extensions which provide nothing but syntactic sugar...
Edit: Anonymous unions were added in C11, so they are now a standard part of the language. Presumably GCC's -std=c11 lets you use them.
I'm finding this question about a year and a half after everybody else did, so I can give a different answer: anonymous structs are not in the C99 standard, but they are in the C11 standard. GCC and clang already support this (the C11 standard seems to have lifted the feature from Microsoft, and GCC has provided support for some MSFT extensions for some time).
Well, the solution was to name instance of the union (which can remain anonymous as datatype) and then use that name as a proxy.
$ diff -u old_us.c us.c
--- old_us.c 2010-07-12 13:49:25.000000000 +0200
+++ us.c 2010-07-12 13:49:02.000000000 +0200
## -15,7 +15,7 ##
union {
struct int_node int_n;
struct double_node double_n;
- };
+ } data;
};
int main(void) {
## -23,6 +23,6 ##
i.value = 10;
struct node n;
n.type = t_int;
- n.int_n = i;
+ n.data.int_n = i;
return 0;
}
Now it compiles as c99 without any problems.
$ cc -std=c99 us.c
$
Note: I am not happy about this solution anyway.
Just for clarifications about anonymous struct or anonymous union.
C11
6.7.2.1 Structure and union specifiers
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.
C99 There are no anonymous struct or union
Simplified: Type-specifier Identifier { Declaration-list } Tags ;
Type-specifier: struct or union;
Identifier: optional, your custom name for the struct or union;
Declaration-list: members, your variables, anonymous struct and anonymous union
Tags: optional. If you have a typedef in front of the Type-specifier, the Tags are alias and not Tags.
It is a anonymous struct or anonymous union only if it have no identifier and no tag, and exist inside another struct or union.
struct s {
struct { int x; }; // Anonymous struct, no identifier and no tag
struct a { int x; }; // NOT Anonymous struct, has an identifier 'a'
struct { int x; } b; // NOT Anonymous struct, has a tag 'b'
struct c { int x; } C; // NOT Anonymous struct
};
struct s {
union { int x; }; // Anonymous union, no identifier and no tag
union a { int x; }; // NOT Anonymous union, has an identifier 'a'
union { int x; } b; // NOT Anonymous union, has a tag 'b'
union c { int x; } C; // NOT Anonymous union
};
typedef hell: if you have a typedef the tag part is not a tag anymore, it is alias for that type.
struct a { int x; } A; // 'A' is a tag
union a { int x; } A; // 'A' is a tag
// But if you use this way
typedef struct b { int x; } B; // 'B' is NOT a tag. It is an alias to struct 'b'
typedef union b { int x; } B; // 'B' is NOT a tag. It is an alias to union 'b'
// Usage
A.x = 10; // A tag you can use without having to declare a new variable
B.x = 10; // Does not work
B bb; // Because 'B' is an alias, you have to declare a new variable
bb.x = 10;
The example bellow just change struct for union, work the same way.
struct a { int x; }; // Regular complete struct type
typedef struct a aa; // Alias 'aa' for the struct 'a'
struct { int x; } b; // Tag 'b'
typedef struct b bb; // Compile, but unusable.
struct c { int x; } C; // identifier or struct name 'c' and tag 'C'
typedef struct { int x; } d; // Alias 'd'
typedef struct e { int x; } ee; // struct 'e' and alias 'ee'
Union must have a name and be declared like this:
union UPair {
struct int_node int_n;
struct double_node double_n;
};
UPair X;
X.int_n.value = 12;
Another solution is to put the common header value (enum node_type type) into every structure, and make your top-level structure a union. It's not exactly "Don't Repeat Yourself", but it does avoid both anonymous unions and uncomfortable looking proxy values.
enum node_type {
t_int, t_double
};
struct int_node {
enum node_type type;
int value;
};
struct double_node {
enum node_type type;
double value;
};
union node {
enum node_type type;
struct int_node int_n;
struct double_node double_n;
};
int main(void) {
union node n;
n.type = t_int; // or n.int_n.type = t_int;
n.int_n.value = 10;
return 0;
}
Looking at 6.2.7.1 of C99, I'm seeing that the identifier is optional:
struct-or-union-specifier:
struct-or-union identifier-opt { struct-declaration-list }
struct-or-union identifier
struct-or-union:
struct
union
struct-declaration-list:
struct-declaration
struct-declaration-list struct-declaration
struct-declaration:
specifier-qualifier-list struct-declarator-list ;
specifier-qualifier-list:
type-specifier specifier-qualifier-list-opt
type-qualifier specifier-qualifier-list-opt
I've been up and down searching, and cannot find any reference to anonymous unions being against the spec. The whole -opt suffix indicates that the thing, in this case identifier is optional according to 6.1.