OOP Course
Сьогодні

Підрозділ 2.10

Явні та неявні перетворення

Пояснює явні та неявні перетворення, механіку доповнення бітів, checked-контекст і поведінку при переповненні.

2.10. Явні та неявні перетворення

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

Явні та неявні перетворення

Неявні перетворення

Неявне перетворення (implicit conversion) — це таке перетворення, яке компілятор виконує автоматично, без жодних явних вказівок у коді. Розробнику достатньо просто записати значення у змінну іншого типу, і все відбувається само собою.

Неявні перетворення можливі лише в тих випадках, коли вони гарантовано безпечні — тобто коли жодне значення вихідного типу не може вийти за межі цільового типу. Саме тому компілятор без вагань виконує, наприклад, byteint: будь-яке значення byte (0–255) без проблем вписується в int (–2 млрд до +2 млрд).

Розширення зі знаком (sign extension)

Коли неявно розширюється беззнаковий тип (наприклад, byte), ліворуч додаються нулі. Це називається доповненням нулями. Але коли розширюється знаковий тип (sbyte, short, int), механізм інший: ліворуч додається копія знакового розряду (старшого біту). Для позитивних чисел знаковий розряд дорівнює 0 — додаються нулі. Для від'ємних він дорівнює 1 — додаються одиниці. Завдяки цьому від'ємне число після розширення залишається від'ємним і зберігає своє значення:

Розглянемо розширення позитивного числа. Знаковий біт 0 — ліворуч додаються нулі:

Sign extension позитивного числа: sbyte 4 → short

Розширення від'ємного числа: знаковий біт 1 — ліворуч додаються одиниці, завдяки чому від'ємне значення зберігається:

Sign extension від'ємного числа: sbyte -4 → short

Без цього механізму розширення знакових від'ємних чисел давало б абсолютно невірний результат — замість -4 отримали б якесь величезне позитивне число.

Явні перетворення

Явне перетворення (explicit conversion) — це перетворення, яке компілятор не може виконати автоматично без явної вказівки розробника. Причина в тому, що такі перетворення потенційно небезпечні: не для всіх значень вихідного типу гарантується коректний результат у цільовому типі. Розробник повинен сам сказати: «Я розумію ризик і беру відповідальність».

Синтаксис явного приведення:

(цільовий_тип) вираз

Безпечні ланцюжки неявних перетворень

Компілятор дозволяє такі неявні перетворення, де є гарантія відсутності втрат:

byte  → short → int → long → decimal
int   → double
short → float  → double
char  → int    → long

Таблиця безпечних неявних перетворень

Усе, що виходить за межі цих ланцюжків, вимагає явного (тип). Зокрема, хоча decimal технічно «більший» за double (28–29 значущих цифр проти 15–16), пряме неявне перетворення між ними не підтримується ні в якому напрямку. Ці типи принципово різні за структурою: double — це IEEE 754 бінарне число з плаваючою точкою, а decimal — десяткове число з фіксованою точністю. Пряме перетворення між ними може призвести до незначних похибок, тому компілятор змушує розробника зробити це явно:

Втрата даних при явному перетворенні

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

Чому 121? Число 633 у двійковому вигляді — 10 01111001. Тип byte зберігає лише молодші 8 біт: 01111001 — це 121. Старший біт 1 відкинутий. Програма не повідомить про помилку — вона просто продовжить роботу з неправильним значенням. Саме це й є найнебезпечнішим у переповненні: помилка залишається прихованою.

Ключове слово `checked`

Щоб захиститись від мовчазного переповнення, C# надає ключове слово checked. Воно змушує середовище виконання перевіряти, чи не виходить результат арифметичної операції або приведення за межі цільового типу. Якщо виходить — кидається виняток OverflowException.

Без checked — програма мовчки дасть 121. З checked — виняток зупинить виконання в місці переповнення, і ми одразу побачимо проблему. Це особливо важливо в математично критичних місцях — розрахунках доз ліків, фінансових транзакціях або алгоритмах, де точність є необхідністю.

Існує також протилежне ключове слово unchecked — воно явно вказує, що переповнення дозволене і не має кидати виняток. Це стандартна поведінка за замовчуванням, але unchecked може знадобитися всередині checked-блоку, якщо для якоїсь конкретної операції переповнення є навмисним:

checked і unchecked можна застосовувати як до окремого виразу (через дужки), так і до цілого блоку коду:

checked
{
    // Усі арифметичні операції в цьому блоці перевіряються
    int x = int.MaxValue;
    int y = x + 1;  // OverflowException
}

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

Комплексний приклад: зважений розрахунок дози

Розроблено Tomka Yurii · © 2026 ·