Сполука — це змінна, яка може втримувати (в різний час) об'єкти різного типу та розміру, компілятор обчислюючи розміри та умови вирівнювання. Сполуки забезпечують можливістю маніпулювання різного роду даними, збереженими в єдиному місці, без потреби включення в програму якоїсь машинозалежної інформації. Вони аналогічні варійованим записам в Pascal.
Для прикладу, який можна віднайти, скажімо, в керівникові символів компілятора, припустімо, що константа може бути int, float або покажчиком на символьний масив. Значення певної константи потрібно зберегти у змінній відповідного типу, однак найзручнішим для керівника символів буде, щоб це значення займало ту саму кількість пам'яті та зберігалося в тому самому місці, незалежно від типу. Саме для цієї мети існують сполуки — єдина змінна, яка може легітимно утримувати будь-який із вказаних типів. Синтаксис основується на тому, що притаманний структурам:
union u_tag {
int ival;
float fval;
char *sval;
} u;
Змінна u буде достатньо великою, щоб утримати найбільше з цих трьох типів; певний розмір залежить від реалізації. Будь-який з цих типів можна присвоїти u і потім використати в якомусь виразі за умови, що використання буде несуперечливим: отриманий тип повинен збігатися з типом, збереженим останнього разу. Саме на програміста падає відповідальність за тим, щоб стежити за тим який тип в дану мить збережено в сполуці; результат залежить від реалізації, якщо щось збережено як один тип, а добуто як інший.
Синтаксично доступ до членів сполуки здійснюється як
назва-сполуки.член
або
покажчик-на-сполуку->член
точно так, як це відбувається в структурах. Якщо для слідкування за тим який тип у дану мить збережено в сполуці u використати змінну utype, тоді ви можете зустріти код подібний на наступне
if (utype == INT)
printf("%d\n", u.ival);
if (utype == FLOAT)
printf("%f\n", u.fval);
if (utype == STRING)
printf("%s\n", u.sval);
else
printf("bad type %d in utype\n", utype);
Сполуки можна зустріти всередині структур і масивів, а також навпаки. Синтаксис доступу до члена сполуки розміщеного в структурі (і навпаки) тотожний гніздованим структурам. Наприклад, в структурному масиві, означеному як
struct {
char *name;
int flags;
int utype;
union {
int ival;
float fval;
char *sval;
} u;
} symtab[NSYM];
до члена ival можна звернутися як
symtab[i].u.ival
а до першого символу ланцюжка sval одним із наступних
*symtab[i].u.sval
symtab[i].u.sval[0]
Насправді сполука, це структура в якій всі члени мають зміщення відносно бази рівне нулю, структура достатньо велика, щоб утримати найбільшого члена, і вирівнювання придатне для всіх типів у сполуці. Стосовно сполук так само як структур застосовні ті самі операції: присвоєння або копіювання як цілого, здобуття адреси і доступ до одного з членів. Сполуку можна ініціювати тільки величиною того самого типу що її перший член; таким чином сполуці u вище можна присвоїти початкове значення тільки у вигляді int.
Розподільник пам'яті з Розділу 8 демонструє як можна використати сполуку, щоб змусити вирівнювання змінної з певною межою пам'яті.