Reputation: 1055
Isn't it true that members in union are exclusive, you can't refer to the other if you already refer to one of them?
union Ptrlist
{
Ptrlist *next;
State *s;
};
void
patch(Ptrlist *l, State *s)
{
Ptrlist *next;
for(; l; l=next){
next = l->next;
l->s = s;
}
}
But the above is referring to both next
and s
at the same time, anyone can explain this?
Upvotes: 3
Views: 397
Reputation: 239851
No, it's not true. You can use any member of a union at any time, although the results if you read a member that wasn't the one most recently written to are a little bit complicated. But that isn't even happening in your code sample and there's absolutely nothing wrong with it. For each item in the list its next
member is read and then its s
member is written, overwriting its next
.
Upvotes: 1
Reputation: 2441
An union is similar to a struct, but it only allocates memory for a variable. The size of the union will be equal to the size of the largest type stored in it. For example:
union A {
unsigned char c;
unsigned short s;
};
int sizeofA = sizeof(A); // = 2 bytes
union B {
unsigned char c[4];
unsigned short s[2];
unsigned int i;
};
int sizeofB = sizeof(B); // = 4 bytes
In the second example, s[0] == (c[1] << 8) & #ff00 | c[0];
. The variables c, s and i overlap.
B b;
// This assignment
b.s[0] = 0;
// is similar to:
b.c[0] = 0;
b.c[1] = 0;
An union is restricted to primitive types and pointers. In C++, you cannot store classes in a union. All other rules remain basically the same as for a structure, such as public access, stack allocation and such.
Thus, in your example you must use a struct instead of an union.
Upvotes: 0
Reputation: 19339
As others have already pointed out, all members of a union are active at all times. The only thing to consider is whether the members are each in a valid state.
If you ever do want some level of exclusivity, you would instead require a tagged union. The basic idea is to wrap the union in a struct, and the struct has a member identifying which element in the union should be used. Take this example:
enum Tag {
FIRST,
SECOND
};
struct {
Tag tag;
union {
int First;
double Second;
};
} taggedUnion;
Now taggedUnion
could be used like:
if(taggedUnion.tag == FIRST)
// use taggedUnion.First;
else
// use taggedUnion.Second
Upvotes: 2
Reputation: 1004
See http://publications.gbdirect.co.uk/c_book/chapter6/unions.html for an introductory discussion on unions.
Basically, it's an easy way to do type casting in advance. So, instead of having
int query_my_data(void *data, int data_len) {
switch(data_len) {
case sizeof(my_data_t): return ((my_data_t *)data)->value;
case sizeof(my_other_data_t): return ((my_other_data_t *)data)->other_val;
default: return -1;
}
You could simplify it by doing
typedef struct {
int data_type;
union {
my_data_t my_data;
my_other_data_t other_data;
} union_data;
} my_union_data_t;
int query_my_data(my_union_data_t *data) {
switch(data->data_type) {
case TYPE_MY_DATA: return data->union_data.my_data.value;
case TYPE_MY_OTHER_DATA: return data->union_data.other_data.other_val;
default: return -1;
}
Where my_data and other_data would have the same starting address in memory.
Upvotes: 0
Reputation:
You are performing an assignment to next
from l->next
. Then, you "overwrite" l->s
through the assignment l->s = s
.
When you assign to l->s
, it overwrites the memory held in l->next
. If next
and s
are the same "size", then both likely could be "active" at the same time.
Upvotes: 1
Reputation: 12343
A union only defines that
&l->next == &l->s
that's all. There is no language-restriction of first accesses.
Upvotes: 5
Reputation: 9424
Yes it's supposed to be like that. Both *s and *next point to the same memory location. And you can use both at the same time.. they are not exclusive.
Upvotes: 1