Объединения


C Unions по сути такие же, как C Structures, за исключением того, что вместо того, чтобы содержать несколько переменных, каждая со своей собственной памятью, Union позволяет использовать несколько имен для одной и той же переменной. Эти имена могут обрабатывать память как разные типы (и размер объединения будет размером самого большого типа + любое дополнение, которое компилятор может решить дать ему)

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

union intParts {
  int theInt;
  char bytes[sizeof(int)];
};

Позволяя вам просматривать каждый байт по отдельности, не применяя указатель и не используя арифметику указателя:

union intParts parts;
parts.theInt = 5968145; // arbitrary number > 255 (1 byte)

printf("The int is %i\nThe bytes are [%i, %i, %i, %i]\n",
parts.theInt, parts.bytes[0], parts.bytes[1], parts.bytes[2], parts.bytes[3]);

// vs

int theInt = parts.theInt;
printf("The int is %i\nThe bytes are [%i, %i, %i, %i]\n",
theInt, *((char*)&theInt+0), *((char*)&theInt+1), *((char*)&theInt+2), *((char*)&theInt+3));

// or with array syntax which can be a tiny bit nicer sometimes

printf("The int is %i\nThe bytes are [%i, %i, %i, %i]\n",
    theInt, ((char*)&theInt)[0], ((char*)&theInt)[1], ((char*)&theInt)[2], ((char*)&theInt)[3]);

Комбинируя это со структурой, вы можете создать «помеченное» объединение, которое можно использовать для хранения нескольких различных типов, по одному за раз.

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

struct operator {
    int intNum;
    float floatNum;
    int type;
    double doubleNum;
};

Поскольку в вашей программе их много и для всех переменных требуется слишком много памяти, вы можете использовать это:

struct operator {
    int type;
    union {
      int intNum;
      float floatNum;
      double doubleNum;
    } types;
};

Таким образом, размер структуры - это просто размер int type+ размер самого большого типа в объединении (double). Небольшой выигрыш, всего 8 или 16 байт, но эту концепцию можно применить к аналогичным структурам.

использовать:

operator op;
op.type = 0; // int, probably better as an enum or macro constant
op.types.intNum = 352;

Кроме того, если вы не дадите объединению имя, доступ к его членам будет осуществляться непосредственно из структуры:

struct operator {
    int type;
    union {
        int intNum;
        float floatNum;
        double doubleNum;
    }; // no name!
};

operator op;
op.type = 0; // int
// intNum is part of the union, but since it's not named you access it directly off the struct itself
op.intNum = 352;

Другая, возможно, более полезная функция - это когда у вас всегда есть несколько переменных одного и того же типа, и вы хотите иметь возможность использовать как имена (для удобства чтения), так и индексы (для упрощения итерации), в этом случае вы можете сделать что-то вроде это:

union Coins {
    struct {
        int quarter;
        int dime;
        int nickel;
        int penny;
    }; // anonymous struct acts the same way as an anonymous union, members are on the outer container
    int coins[4];
};

В этом примере вы можете видеть, что есть структура, которая содержит четыре (обычных) монеты в Соединенных Штатах.

поскольку объединение заставляет переменные совместно использовать одну и ту же память, массив монет совпадает с каждым int в структуре (по порядку):

union Coins change;
for(int i = 0; i < sizeof(change) / sizeof(int); ++i)
{
    scanf("%i", change.coins + i); // BAD code! input is always suspect!
}
printf("There are %i quarters, %i dimes, %i nickels, and %i pennies\n",
    change.quarter, change.dime, change.nickel, change.penny);

Упражнение

Создайте объединение, в котором хранится массив из 21 символа и 6 целых чисел (6, поскольку 21/4 == 5, но 5 * 4 == 20, поэтому вам понадобится еще 1 для целей этого упражнения), вы установите целые числа равными 6 заданные значения, а затем распечатать массив символов как серию символов, так и строку.