Поля і об‘єднання
Поля і об‘єднання є особливим різновидом записів. Поле — це послідовність сусідніх двійкових розрядів (битий) усередині одного цілого значення. Воно може мати тип signed int або unsigned int і займати від 1 до 16 біт. Поля розміщуються в машинному слові в напрямі від молодших до старших розрядів. Наприклад, запис
struct prim { int a:2; unsigned b:3; int:5;
Int с: 1; unsigned d:5; } I, j;
забезпечує розміщення, показане на рис. 41.
Розряди машинного слова
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
|||
D |
с |
Не використовуються |
b |
а |
|
Рис.1 – Структура поля
У полях типу signed крайній лівий біт є знаковим. Наприклад, таке поле шириною 1 біт може тільки зберігати значення -1 і 0, оскільки будь-яка ненульова величина інтерпретуватиметься як -1.
Поля використовуються для упаковки значеннь декількох змінних в одне машинне слово з метою економії пам'яті. У оголошенні полів найчастіше використовується модифікатор unsigned. Вони не можуть бути масивами і не мають адрес, тому до них не можна застосувати унарну операцію & .
Використання полів розглянемо на прикладі такої програми:
/* Демонстрація полів */
#include <stdio h>
struct { unsigned a:l;
unsigned b:l;
unsigned у:1;
unsigned c:2; } f;
/* оголошення змінної f, що містить три
однорозрядних і одне двохрозрядне поле (число,
наступне за двокрапкою, задає кількість розрядів
в полі ) */
main ()
{
int i;
printf(“розмір f =%d байтів\n", sizeof(f));
f.a=f.b=1; /*в поля f.a і f.b записуються одиниці */
for(i=0; i<2; i++) {
f.y=f.a&&f.b;/* обчислюється кон'юнкція f.y змінних f.a i f.b */
printf(“цикл %d; f.y=%d\n”, i, f.y);
f.b=0; } /* в полі f.b записується нуль */
f.c=f.a +!f.b; /*арифметичне складання значення f.a (воно дорівнює
одиниці) і заперечення значення f.b (заперечення нуля
теж дорівнює одиниці); в результаті f.c = 2 */
printf(“f.c=%d", f.c);
}
Оголошення вигляду unsigned а:1; визначає однобітове поле а; у нього можна записати тільки одне з двох значень: нуль або одиницю. Оголошення unsigned c:2, визначає двобітове поле с; у нього вже можна записати одне з чотирьох значень: 0,1, 2 або 3. Функція sizeof(f) дозволяє визначити розмір в байтах одного запису f . Аналогічно з її допомогою можна знаходити і розміри інших об'єктів (змінних, масивів і т.п.).
Звернення до будь-якого поля здійснюється так само, як до елементу запису. Наприклад, f.а – звернення до однобітового поля а.
Результати роботи програми мають вигляд:
розмір f = 2 байти
цикл 0; f.y=1
цикл 1; f.y=0
f.с= 2
Об‘єднання – це деяка змінна, яка може зберігати (у різний час) об'єкти різних типу і розміру. В результаті з'являється можливість роботи в одній і тій же області пам'яті з даними різного вигляду. Для опису об‘єднання використовується ключове слово union (об'єднання), а відповідний синтаксис аналогічний синтаксису записів.
Наступна програма пояснює використання об‘єднань:
/* Демонстрація об‘єднань */
#include <stdio.h>
union r { int ir; float fr; char cr; } z;
/* оголошення об‘єднання z типу r; змінна z достатньо
велика, щоб зберігати найбільший з трьох приведених
типів (тут union – ключове слово об‘єднання */
main()
{ рrintf(“розмір z - %d байтів\n", sizeof(z));
printf("введіть значення z.ir\n");
scanf(“%d%”, &z.ir);
printf(“значення ir = %d\n", z.ir);
рrintf(“введіть значення z.fr\n" );
scanf(“%f", &z.fr);
рrintf(“значення fr =%f\n", z.fr );
printf(“ введіть значення z.сr\n" );
scanf("%ls” &z.cr);
printf("значення cr = %c\n", z.cr);
}
У функції scanf ("%ls", &z.cr); задана специфікація перетворення %ls. Якщо використовувати звичну для одного символу специфікацію %с, то в програму завжди заноситиметься керуючий символ, що відповідає клавіші ВВЕДЕННЯ. Ця клавіша натискалась раніше для введення значення змінної z.fr.
Результати роботи програми мають вигляд:
розмір z = 4 байтів
введіть значення z.ir
7
значення ir : 7
введіть значення z.fr
8.3456678
значення fr = 8.345668
введіть значення z.сr
p
значення cr = р
У мові СІ можна вводити імена для нових типів даних за допомогою ключового слова typеdef (визначити тип). Наприклад, опис typedef int INTEGER; робить слово INTEGER синонімом int. Тепер його можна використовувати в оголошеннях типу, так само як int.
Як приклад розглянемо приведену нижче програму:
/* Приклад визначення типу */
#include <stdio b>
typedef float REAL; /* ім'я REAL робиться синонімом float
(тепер в описах відповідного типу можна
використовувати і float, і BEAL ) */
main()
{ REAL а;
printf( "Ввести значення а\n"),
scаnf(“%f”, &а);
printf(“a=%f”, а);
}
Результати її роботи:
Ввести значення а
9.4567
а= 9.456700
Далі будуть приведені складніші приклади використання опису typedef.