- •1.1 Перші кроки
- •1.2 Змінні й арифметичні вирази
- •1.3 Твердження for
- •1.4 Символічні константи
- •1.5 Ввід і вивід знаків
- •1.5.1 Копіювання файла
- •1.5.2 Відлік символів
- •1.5.3 Відлік рядків
- •1.6 Масиви
- •1.7 Функції
- •1.8 Аргументи - виклик за значенням
- •1.9 Символьні масиви
- •1.10 Зовнішні змінні й область дії
- •2.1 Назви змінних
- •2.2 Типи даних і розміри
- •2.3 Константи
- •2.4 Оголошення
- •2.5 Арифметичні операції
- •2.6 Реляційні та логічні оператори
- •2.7 Перетворення типів
- •2.8 Оператори приросту та спаду
- •2.9 Розрядні оператори
- •2.10 Оператори та вирази присвоєння
- •2.11 Вирази умов
- •2.12 Пріоритет і послідовність обчислення
- •3.1 Вирази та блоки
- •3.3 Else if
- •3.4 Switch
- •3.5 Цикли while та for
- •3.6 Цикли do-while
- •3.7 Break і continue
- •3.8 Goto та мітки
- •4.1 Основні знання про функції
- •4.2 Функції, які не повертають цілих
- •4.3 Зовнішні змінні
- •4.4 Правила області дії
- •4.5 Файли заголовка
- •4.6 Статичні змінні
- •4.7 Регістрові змінні
- •4.8 Структура блоків
- •4.10 Рекурсія
- •4.11 Препроцесор c
- •4.11.1 Включення файлів
- •4.11.2 Заміна макросів
- •4.11.3 Обумовлене включення файлів
- •5.1 Покажчики й адреси
- •5.2 Покажчики й аргументи функцій
- •5.3 Покажчики та масиви
- •5.4 Арифметика адрес
- •5.5 Покажчики на символи та функції
- •5.6 Масив покажчиків; покажчики на покажчики
- •5.7 Багатовимірні масиви
- •5.8 Ініціалізація масиву покажчиків
- •5.9 Покажчики в порівнянні з багатовимірними масивами
- •5.10 Аргументи командного рядка
- •5.11 Покажчики на функції
- •5.12 Складні оголошення
- •6.1 Основні поняття про структури
- •6.2 Структури та функції
- •6.3 Масиви структур
- •6.4 Покажчики на структури
- •6.5 Структури зі зворотнім звертанням
- •6.6 Пошук по таблиці
- •6.7 Typedef
- •6.8 Сполуки
- •6.9 Розрядні поля
- •7.1 Стандартний ввід і вивід
- •7.2 Форматований вивід - printf
- •7.3 Списки аргументів довільної довжини
- •7.4 Форматований ввід - scanf
- •7.5 Доступ до файлів
- •7.6 Обробка помилок - stderr і exit
- •7.7 Ввід і вивід рядків
- •7.8 Додаткові функції
- •7.8.1 Операції з ланцюжками
- •7.8.2 Перевірка і перетворення класів символів
- •7.8.3 Ungetc
- •7.8.4 Виконання команд
- •7.8.5 Керування пам'яттю
- •7.8.6 Математичні функції
- •7.8.7 Генератор випадкових чисел
- •8.1 Дескриптори файлів
- •8.2 Низькорівневий ввід/вивід - read і write
- •8.3 Open, creat, close, unlink
- •8.4 Довільний доступ - lseek
- •8.5 Приклад: втілення fopen і getc
- •8.6 Приклад - перелік вмісту каталогів
- •8.7 Приклад - розподільник пам'яті
6.8 Сполуки
Сполука — це змінна, яка може втримувати (в різний час) об'єкти різного типу та розміру, компілятор обчислюючи розміри та умови вирівнювання. Сполуки забезпечують можливістю маніпулювання різного роду даними, збереженими в єдиному місці, без потреби включення в програму якоїсь машинозалежної інформації. Вони аналогічні варійованим записам в 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 демонструє як можна використати сполуку, щоб змусити вирівнювання змінної з певною межою пам'яті.
