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);
Related
I come across a nested structure & union with the following syntax. I am not sure how the following syntax needs to be corrected.
typedef struct 1
{
..
..
union
{
struct
{
..
..
}var1;
struct
{
...
...
...
}var2;
}
..
..
}name_to_struct1
Can someone explain what is wrong here, and how the syntax must be given. I see the error thrown is "struct 1" has no member named var1
NOTE: The compiler I am using is not a C11, so this type of unnamed structure/union should be avoided.
I am kind of out of ideas here, I have never heard about this compiler, cannot find anything about it online. So, my last idea, is the following: name the union as well:
#include <stdio.h>
typedef struct {
union {
struct {
int a;
double b;
} var1;
struct {
int c;
double d;
} var2;
} uni;
} name_to_struct1;
int main(int argc, char* argv[]) {
name_to_struct1 asd;
asd.uni.var1.a = 1;
printf("%d\n", asd.uni.var1.a);
return 0;
}
If unnamed structs and unions are not allowed, maybe this could help.
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.
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 );
I wonder if the the following C code is valid:
struct A {
struct B {
int value;
} b;
};
struct B;
void func1(struct B* b) {
b->value = 42;
}
void func2() {
struct A a;
func1(&a.b);
}
This code compiles with gcc and works as one might expect whereas a code checker complains and I wonder who is right and if this is acceptable by the standard (C90 or C99) to refer to struct B in this form.
Yes you can but you will have an error if you want use Struct B outside Struct A.
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.