Reputation: 360
With an anonymous union declared in a struct, you can access the members directly. This made sense and I thought, like a normal union, you could only read from the most recent value that has been written to. Then I saw this
#include<stdio.h>
struct Scope
{
// Anonymous union
union
{
char alpha;
int num;
};
};
int main()
{
struct Scope x;
x.num = 65;
// Note that members of union are accessed directly
printf("x.alpha = %c, x.num = %d", x.alpha, x.num);
return 0;
}
What then, is the point if I can just access all of the variables all of the time? Why not just declare the variables in the scope of "Scope"?
Upvotes: 2
Views: 1739
Reputation: 213711
The point is that struct Scope
could have other members. A more realistic example:
struct Scope
{
union
{
int num;
uint8_t num_byte [sizeof(int)];
};
int foo;
};
Now you can access struct Scope
members as obj.num
or obj.num_byte[i]
. After that union in memory, there will be a different variable foo
, so clearly the union members can't get moved out to the struct.
If not for anonymous union, we'd have to type something like obj.name.num
, where name is potentially just clutter.
Regarding reading different union members, your statement "you could only read from the most recent value that has been written to" is not true in C. Note that C and C++ are different here.
C17 6.5.2.3 states:
A postfix expression followed by the . operator and an identifier designates a member of a structure or union object. The value is that of the named member,95) and is an lvalue if the first expression is an lvalue.
where the foot note 95) is helpful:
95) If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.
The part in 6.2.6 referred to by the foot note:
When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.
Where an operator is applied to a value that has more than one object representation, which object representation is used shall not affect the value of the result. Where a value is stored in an object using a type that has more than one object representation for that value, it is unspecified which representation is used, but a trap representation shall not be generated.
What this means in plain English is that C allows type punning, but it's the programmers responsibility to ensure that it is feasible, with regards to alignment/padding, trap representations, endianess etc.
Upvotes: 4
Reputation: 58032
According to C11 6.2.6.1, the value of the accessed member is unspecified. In general, it could be a trap representation, which triggers undefined behavior.
(If you changed char
to unsigned char
, it would be safe, since unsigned char
cannot have trap representations. So your program would run to completion and print something, but the C standard does not specify what value would be printed for x.alpha
.)
Of course, any given implementation may specify what value you actually get (e.g. the low byte, or the high byte, of x.num
). So such code is most likely intended to work only on such implementations, and not meant to be portable or standard-conforming.
As Peter notes, all this is independent of whether you use anonymous unions or the old-fashioned kind.
Upvotes: 4
Reputation: 379
You can interpret same memory segment differently. Its widely used in protocols implementations. Where you receive buffer of bytes and based on various flags treat/decode it as needed.
In this example int and char are different size and byte order
Upvotes: 1