Принципи типізації даних

Основи сучасного програмування Основи сучасного програмування Основи сучасного програмування Основи сучасного програмування Основи сучасного програмування Основи сучасного

Застосування програм у самих різних сферах людської діяльності привело до необхідності підвищення надійності всього програмного забезпечення. Одним з напрямів підвищення надійності і, відповідно, удосконалення мов програмування став розвиток типізації даних. Теорія типів даних виходить із того, що кожне з даних, які використовуються в програмі, належить одному й тільки одному типу. Тип даного визначає множину його можливих значень і набір операцій, що можуть виконуватись над ним. Дані конкретного типу в деяких випадках можуть бути перетворені на дані іншого типу. Такі перетворення можуть бути явними чи неявними в деяких мовах.

Автоматичне виявлення помилок може здійснюватися або компілятором, або системою, що підтримує виконання скомпільованої програми. Розглянемо приклад. Припустимо, що масив а, який складається із 20 цілих чисел, індексується цілою змінною i таким чином, що i- та компонента масиву а позначається a [ i ]. Очевидно, що надійна програма має забезпечити виконання умови 1 20 у будь-якому місці, де зустрічається a [ i ].

Для цього існують дві можливості. Традиційний підхід полягає в простому внесенні в готову програму перед кожним звертанням до масиву додаткового коду, що перевіряє виконання необхідної умови. Сучасніший підхід полягає в перевірці значення змінної i не під час її використання, а скоріше, під час присвоювання. Це вимагає додаткових зусиль програміста, що має специфікувати область значень i при описі змінної. Через те, що заданий тип змінної i обмежує можливі значення областю від 1 до 20, немає необхідності взагалі перевіряти значення індексупри звертанні до a [ i ]. Замість цього перевіряються значення, що присвоюються змінній i. Дуже часто законність таких присвоювань може бути перевірена під час компіляції, так що загальний обсяг фактично необхідного об'єктного коду перевірки допустимих значень i істотно зменшується. Ще однією перевагою такого підходу є те, що при цьому зростає ясність програм, адже область значень, яких набуває кожна змінна, установлюється явно.

Усі універсальні мови програмування, незважаючи на розходження в синтаксисі та ключових словах, реалізують ті самі канонічні структури: оператори присвоювання, цикли й розгалуження. В усіх сучасних мовах присутні визначені (базові) типи даних (цілі та дійсні арифметичні типи, символьний і, можливо, рядковий тип), є можливість використання об'єктів даних, у тому числі масивів і структур (записів). Для арифметичних даних дозволені звичайні арифметичні операції, для об'єктів даних зазвичай передбачені тільки операція присвоювання й можливість звертання до елементів.

У наступному підрозділі ми лише коротко розглянемо типи даних, що використовуються при програмуванні задач.

Прості типи даних

Інформація, подана кожним словом даних у пам'яті, може бути різною. Наприклад, деякі слова можуть містити цілі числа, інші – символи. Сучасна мова високого рівня дає програмісту абстрактну модель, у якій дані й операції над даними можна специфікувати в об'єк­тно-орієнтованих поняттях. При цьому мова високого рівня забезпечує такі можливості доступу до об'єктів даних у пам'яті:

a на об'єкти даних посилаються за допомогою визначених користувачем імен (ідентифікаторів);

a об'єкти даних пов'язані з типом, що визначає множину значень, які можуть приймати об'єкти цього типу, і множину операцій, що можуть застосовуватися до об'єктів цього типу.

У ранніх мовах введення поняття типу даних було чисто прагматичним прийомом, який застосовували з метою полегшити роботу компілятору. І справді, користувач звертав мало уваги на поняття типу. Для сучасних мов розроблені дуже складні механізми типів, що дозволяють програмісту розв'язувати задачі з більшою чіткістю та значно вищою надійністю. Налагоджений механізм типів є ключовим чинником при забезпеченні надійності мови програмування, що має першорядне значення при програмуванні в реальному часі.

У сучасних мовах є множина стандартних типів даних (прості типи) і операцій та існують механізми для специфікації типів, що визначаються користувачем. Загальними для більшості мов є чотири простих типи даних:

a цілий;

a дійсний;

a логічний;

a символьний.

Розглянемо можливості, що забезпечуються мовами програмування для типізації даних;

a кожен тип визначає множину значень і множину операцій над даними цього типу;

a у кожній операції присвоювання тип значення, що присвоюється, і тип об'єкта даних, якому здійснюється присвоювання, мають бути еквівалентними;

a кожна операція, що застосовується до об'єкта даних, має належати множині операцій, обумовленій типом об'єкта.

Наприклад, ми маємо такі описи змінних:

float x;

int i;

char c;

де float, int, char – ідентифікатори дійсного, цілого та символьного типів відповідно. Ці ідентифікатори використовують для опису змінних простих типів. Тоді присвоювання вигляду

i=x;

c=x;

некоректні, а

x=3.5;

i=7;

цілком законні з погляду синтаксису мови.

Існує механізм перетворення типів для виконання, наприклад, присвоювань

х=(float)i.

Застосування імені типу float до цілого значення змінної i дає дійсний результат.

Усе це підвищує надійність і ясність програми. Усім операціям на абстрактному рівні мови забезпечується коректність.

Похідні типи

Наступним кроком у розробці програми є введення поняття типів даних, визначених користувачем. Це дозволяє істотно підвищити не тільки надійність програмного забезпечення, але й швидкість його розробки.

На абстрактному рівні тип даних можна розглядати як факторизацію визначених властивостей, загальних для конкретного класу об'єктів. Якщо користувач у програмуванні використовуватиме тільки прості типи, то всі об'єкти, що моделюються одним типом, належатимуть одному й тому самому класу просто тому, що вони одного типу. Це, однак, може не відповідати суті цих об'єктів у предметній області та програмі.

Розглянемо задачу підрахунку площі прямокутного трикутника, а також кут при одному з катетів. Значення катетів вводяться з клавіатури.

#include <stdio.h>

/*підключення бібліотек, що містять функції введення-виведення*/void main(void)

/*заголовок функції main, з якої завжди починається виконання С-програми*/

{

/*початок програми*/

float cat1, cat2, square, kut;

/*ідентифікатори cat1, cat2 вводяться для використання в програмі значень катетів, square – для одержання значення площі, kut – для збереження величини кута*/

scanf("%f%f', & cat1, & cat2);

/*за допомогою функції scanf вводимо з клавіатури значення катетів*/

square=cat 1*cat2/2;

/*обчислюємо площу трикутника і значення присвоюємо змінній square*/

kut=atan(cat1/cat2);

printf("square=%f ugol=%f\n', square,kut);

/*за допомогою функції printf друкуємо значення площі трикутника й відповідного кута*/

} /*кінець програми*/

Наведений текст для компіляції помилок не містить, тому програма правильно підрахує площу й величину кута. Наступний, семантично неправильний оператор

square=kut/2;

компілятор пропустить, і результат при виконанні програми буде хибним.

Перевагою похідних типів є можливість написання такої програми:

typedef float znachennia, vel_kut;

/*за допомогою ключового слова typedef вводимо нові типи даних, потім просто посилаємося на введене ім'я типу*/

znachennia cat1, cat2, square;

vel_kut kut;

/*ідентифікатори cat1, cat2 вводяться для використання в програмі значень катетів, square – для одержання значення площі, kyt – для збереження величини кута*/

scanf("%f%f',&cat1,&cat2);

/*за допомогою функції scanf вводимо з клавіатури значення катетів*/

square=cat1*cat2/2;

/*обчислюємо площу трикутника і значення присвоюємо змінній square*/

kut=atan(cat1/cat2);

printf("square=%f kyt=%f \n', square,kut);

/*за допомогою функції printf друкуємо значення площі трикутника й відповідного кута*/

} /*кінець програми*/

У цьому варіанті програми визначаються два нових типи – znachennia і vel_kut – на основі існуючого простого типу float. Описані за допомогою типу znachennia об'єкти містяться явно в класі, логічно відмінному від класу об'єктів, описаних типом vel_kut. Такі нові типи називаються похідними.

Введення в мову похідних типів збільшує її надійність, дозволяючи компілятору, принаймні в принципі, виявляти такі помилки, як

square=kut/2;

Чи виявляється така помилка насправді, залежить від використовуваного в мові програмування методу визначення еквівалентності типів. Виникає також питання, які атрибути успадковує похідний тип від породжуваного.

Зауважимо, що використання похідних типів збільшує, поряд з надійністю, ясність програм. Ім'я типу можна вибрати так, щоб воно відповідало використанню об'єкта цього типу в предметній сфері досліджень.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: