Почему союз может быть использован таким образом? - PullRequest
3 голосов
/ 09 августа 2011

Не правда ли, что члены союза являются эксклюзивными, вы не можете ссылаться на других, если вы уже ссылаетесь на одного из них?

union Ptrlist
{
    Ptrlist *next;
    State *s;
};

void
patch(Ptrlist *l, State *s)
{
    Ptrlist *next;

    for(; l; l=next){
        next = l->next;
        l->s = s;
    }
}

Но вышеизложенное относится к обоим next и s в то же время, кто-нибудь может объяснить это?

Ответы [ 7 ]

5 голосов
/ 09 августа 2011

Объединение только определяет, что

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

вот и все. Нет языкового ограничения при первом доступе.

2 голосов
/ 09 августа 2011

Как уже отмечали другие, все члены профсоюза активны все раза. Единственное, что нужно учитывать, это то, находятся ли члены в действительном состоянии.

Если вы когда-нибудь захотите получить какой-то уровень эксклюзивности, вам понадобится помеченный союз. Основная идея состоит в том, чтобы обернуть объединение в структуру, и структура имеет член, определяющий, какой элемент в объединении следует использовать. Возьмите этот пример:

enum Tag {
    FIRST,
    SECOND
};

struct {
    Tag tag;
    union {
        int First;
        double Second;
    };
} taggedUnion;

Теперь taggedUnion можно использовать как:

if(taggedUnion.tag == FIRST)
    // use taggedUnion.First;
else
    // use taggedUnion.Second
1 голос
/ 09 августа 2011

Нет, это не правда.Вы можете использовать любого члена союза в любое время, хотя результаты, если вы прочитаете члена, который был не самым последним написанным , немного сложнее.Но это даже не происходит в вашем примере кода, и в этом нет абсолютно ничего плохого.Для каждого элемента в списке читается его член next, а затем записывается его член s, перезаписывая его next.

1 голос
/ 09 августа 2011

Да, это должно быть так.И * s, и * следующий указывают на одну и ту же ячейку памяти.И вы можете использовать оба одновременно ... они не являются эксклюзивными.

1 голос
/ 09 августа 2011

Вы выполняете назначение на next из l->next.Затем вы «перезаписываете» l->s через присваивание l->s = s.

Когда вы назначаете l->s, он перезаписывает память, хранящуюся в l->next.Если next и s имеют одинаковый «размер», то оба, вероятно, могут быть «активными» одновременно.

0 голосов
/ 11 августа 2011

Объединение похоже на структуру, но оно только выделяет память для переменной.Размер объединения будет равен размеру самого большого хранимого в нем типа.Например:

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

Во втором примере s[0] == (c[1] << 8) & #ff00 | c[0];.Переменные c, s и i перекрываются.

B b;
// This assignment
b.s[0] = 0;
// is similar to:
b.c[0] = 0;
b.c[1] = 0;

Объединение ограничено примитивными типами и указателями.В C ++ нельзя хранить классы в объединении.Все остальные правила остаются в основном такими же, как и для структуры, такой как открытый доступ, распределение стека и т. Д.

Таким образом, в вашем примере вы должны использовать структуру вместо объединения.

0 голосов
/ 09 августа 2011

См. http://publications.gbdirect.co.uk/c_book/chapter6/unions.html для вступительного обсуждения союзов.

По сути, это простой способ заранее выполнить приведение типов.Таким образом, вместо

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;
  }

Вы можете упростить его, выполнив

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;
  }

, где my_data и other_data будут иметь один и тот же начальный адрес в памяти.

...