Объединения по сравнению со структурами в C

Я исправил это , удалив content_dashboard.xml и поместив весь контент в макет координатора, также заменил hide_bottom_view_on_scroll_behavior с пользовательским поведением

9
задан Étienne 14 June 2013 в 13:57
поделиться

6 ответов

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

|0---1---2---3---|4---|5---6---7---8---|
|ffffffffffffffff|    |                | <- f: Where your float is stored
|                |cccc|                | <- c: Where your char is stored
|                |    |aaaaaaaaaaaaaaaa| <- a: Where your int is stored

Таким образом, при изменении значения f Вы на самом деле изменяете байты 0-3. При изменении символа Вы на самом деле изменяете байт 4. При изменении интервала Вы на самом деле изменяете байты 5-8.

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

|0---1---2---3---|
|ffffffffffffffff| <- f: where your float is stored
|cccc------------| <- c: where your char is stored
|aaaaaaaaaaaaaaaa| <- a: where your int is stored

Таким образом, теперь, когда я изменяю значение f, я изменяю байты 0-3. Так как c хранится в байте 0 при изменении f Вы также изменяете c и a! При изменении c Вы изменяете часть f и - и когда Вы изменяете a, Вы изменяете c и f. Это - то, где Ваша "перезапись" происходит. При упаковке 3 значений в один адрес памяти Вы "не оставляете свободное место" вообще; Вы просто создаете 3 различных способа посмотреть на и изменить те же данные. У Вас действительно нет интервала, плавания и символа в том объединении - на физическом уровне, Вы только что получили 32 бита, которые могли быть просмотрены как интервал, плавание или символ. Изменение того предназначено для изменения других. Если Вы не хотите, чтобы они изменили друг друга, то используйте структуру.

Поэтому gcc говорит Вам, что Ваша структура 9 байтов длиной, в то время как Ваше объединение - только 4 - это не оставляет свободное место - это просто, что структуры и объединения не являются тем же самым.

51
ответ дан 4 December 2019 в 05:50
поделиться

Я думаю, что Вы неправильно понимаете цель a union.

A union, как имя предполагает, определяет структуру, где все ее участники занимают то же пространство памяти. Принимая во внимание, что a struct места каждый из его участников в отдельной памяти в единственной, непрерывной области.

С Вашим объединением, когда Вы пишете:

union foo;
foo.c = 3;

Затем foo.a и foo.f будет оба изменен. Это вызвано тем, что .a, .c, и .f хранятся в той же ячейке памяти. Таким образом каждый член объединения является различным "представлением" той же памяти. Этого не происходит с a struct потому что все участники являются отличными и отдельными друг от друга.

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

39
ответ дан 4 December 2019 в 05:50
поделиться

Объединение содержит ряд взаимоисключающих данных.

В Вашем конкретном примере можно сохранить плавание (f), символ (c) или интервал (a) в объединении. Однако память будет только выделена для самого большого объекта в объединении. Все объекты в объединении совместно используют ту же часть памяти. Другими словами, запись одного значения в объединение, сопровождаемое другим, заставит первое значение быть перезаписанным.

Необходимо возвратиться и спросить себя, что Вы моделируете:

  • Вы действительно хотите, чтобы значения f, c и были взаимоисключающими (т.е. только одно значение может существовать сразу)? Если так, рассмотрите использование объединения в сочетании с перечислением значений (сохраненный вне объединения) указание, какой участник в объединении является "активным" в каком-то конкретном моменте времени. Это позволит Вам извлекать пользу памяти из использования объединения, за счет более опасного кода (поскольку любой поддерживающий его должен будет знать, что значения являются взаимоисключающими - т.е. это - действительно объединение). Только рассмотрите эту возможность, если Вы создаете многие из этих объединений, и сохранение памяти жизненно важно (например, на встроенных центральных процессорах). Вы даже не можете закончить тем, что сохранили память, потому что необходимо будет создать перечислимые переменные на стеке, который поднимет память также.

  • Вы хотите, чтобы эти значения были одновременно активны и не вмешались друг в друга? Если так, необходимо будет использовать структуру вместо этого (поскольку Вы вставляете свой первый пример). Это будет использовать больше памяти - при инстанцировании структуры память, которая выделяется, является суммой всех участников (плюс некоторое дополнение к ближайшей границе слова). Если сохранение памяти не первостепенной важности (см. предыдущий пример), я одобрил бы этот подход.

Править:

(Очень простой) пример того, как использовать перечисления в сочетании с объединением:

typedef union
{
    float f;
    char c;
    int a;
} floatCharIntUnion;

typedef enum
{
    usingFloat,
    usingChar,
    usingInt
} unionSelection;

int main()
{
    floatCharIntUnion myUnion;
    unionSelection selection;

    myUnion.f = 3.1415;
    selection = usingFloat;
    processUnion(&myUnion, selection);

    myUnion.c = 'a';
    selection = usingChar;
    processUnion(&myUnion, selection);

    myUnion.a = 22;
    selection = usingInt;
    processUnion(&myUnion, selection);
}

void processUnion(floatCharIntUnion* myUnion, unionSelection selection)
{

    switch (selection)
    {
    case usingFloat:
        // Process myUnion->f
        break;
    case usingChar:
        // Process myUnion->c
        break;
    case usingInt:
        // Process myUnion->a
        break;
    }
}
9
ответ дан 4 December 2019 в 05:50
поделиться

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

union unin
{
   float f;
   char c;
   int a;
}

Другое использование объединения состоит в том, когда Вы хотите сохранить что-то, что имеет части, позвольте, находился, можно хотеть смоделировать регистр как объединение, содержащее старший байт, младший байт и составное значение. Таким образом, можно сохранить составное значение в объединение и использовать участников для получения частей через других участников.

0
ответ дан 4 December 2019 в 05:50
поделиться

Это - классический пример использования объединения, чтобы хранить данные в зависимости от внешнего маркера.

Интервал, плавание и символ * все занимают то же место в объединении, они не последовательны так, если необходимо сохранить их всех, это - структура, которую Вы ищете, не объединение.

Структура является размером самой большой вещи в объединении плюс размер типа, так как это вне объединения.

#define TYP_INT 0
#define TYP_FLT 1
#define TYP_STR 2

typedef struct {
    int type;
    union data {
        int a;
        float b;
        char *c;
    }
} tMyType;

static void printMyType (tMyType * x) {
    if (x.type == TYP_INT) {
        printf ("%d\n", x.data.a;
        return;
    }
    if (x.type == TYP_FLT) {
        printf ("%f\n", x.data.b;
        return;
    }
    if (x.type == TYP_STR) {
        printf ("%s\n", x.data.c;
        return;
    }
}

Функция printMyType правильно обнаружит то, что хранится в структуре (если Вы не лжете ей), и распечатайте соответствующее значение.

При заполнении одного из них необходимо сделать:

x.type = TYP_INT;
x.data.a = 7;

или

x.type = TYP_STR;
x.data.c = "Hello";

и данный x может только быть одна вещь за один раз.

Горе случается с любым, кто пробует:

x.type = TYP_STR;
x.data.a = 7;

Они напрашиваются на неприятности.

1
ответ дан 4 December 2019 в 05:50
поделиться

Я думаю, что Вы неправильно понимаете Объединения.

Идея позади использования объединений является пальцем ноги, сохраняют память...

да, это - одна причина

... и получите результат, эквивалентный структуре...

нет

это не эквивалентно. Они выглядят подобными в исходном коде, но это - совершенно другая вещь. Как яблоки и самолеты.

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

Когда Вы пишете:

union ABCunion
{
    int a;
    double b;
    char c;
} myAbc;

Вы говорите: "возьмите часть памяти, достаточно большой для самого большого среди интервала, символа и двойного, и позволяет, называют это myAbc.

В той памяти теперь можно сохранить или интервал или двойное, или символ. Если Вы храните интервал и затем храните двойное, интервала не стало навсегда.

Какой смысл затем?

Существует два основного использования для Объединений.

a) Различаемое устройство хранения данных

Это - то, что мы сделали выше. Я выбираю часть памяти, и я даю ей различные значения в зависимости от контекста. Иногда контекст является явным (Вы сохраняете некоторую переменную, которая указывает на то, какой "вид" переменной Вы сохранили), и иногда это может быть неявно (базирующийся раздела кода, можно сказать, какой должен использоваться). Так или иначе код должен смочь понять это, или Вы не сможете сделать что-либо разумное с переменной.

Типичный (явный) пример был бы:

struct MyVariantType
{
    int typeIndicator ;  // type=1 -> It's an int, 
                         // type=2 -> It's a  double, 
                         // type=3 -> It's a  char
    ABCunion body;
};

Например, "Вариантами" VB6 являются Объединения, мало чем отличающиеся от вышеупомянутого (но более сложный).

b) Представление разделения Это иногда полезно, когда необходимо смочь рассматривать переменную или как "целое" или как комбинацию частей. Легче объяснить с примером:

union DOUBLEBYTE
{
    struct
    {
        unsigned char a;
        unsigned char b;
    } bytes;
    short Integer;        
} myVar;

Вот короткое целое "unioned" с парой байтов. Теперь, можно просмотреть то же значение как любого короткое целое (myVar. Целое число), или можно так же, как легко изучить отдельные байты, которые делают часть значения (myVar.bytes.a и myVar.bytes.b).

Обратите внимание, что это второе использование не является портативным (я вполне уверен); подразумевать, что это, как гарантируют, не будет работать через различную архитектуру машины; но это использование абсолютно необходимо для вида задач, для которых C был разработан (реализация ОС).

12
ответ дан 4 December 2019 в 05:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: