lexer
lexer

Reputation: 1055

Why can union be used this way?

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

Answers (7)

hobbs
hobbs

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

npclaudiu
npclaudiu

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

Ken Wayne VanderLinde
Ken Wayne VanderLinde

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

Kaos
Kaos

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

user195488
user195488

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

Patrick B.
Patrick B.

Reputation: 12343

A union only defines that

&l->next == &l->s 

that's all. There is no language-restriction of first accesses.

Upvotes: 5

duedl0r
duedl0r

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

Related Questions