6. Přetečení

Datové typy mají své rozsahy hodnot. V kódu můžeme využít vlastnost MaxValue, která nám vrátí horní mez rozsahu u daného datového typu. Může se stát, že vykonáním aritmetické operace překročíme povolený rozsah. Dojde k tzv. přetečení (anglicky "Overflow"). 

Pokud se chceme v C# pojistit, aby nás kompilátor upozornil, že během početních operací prováděných na celých číslech došlo k přetečení, můžeme využít klíčové slovo checked. Toto slovo nám zajistí, že v případě přetečení budeme upozorněni kompilátorem na tuto nepříjemnou skutečnost. Může se to zdát divné, ale existuje i protipól – klíčové slovo unchecked. To slovo potlačuje hlášení o přetečení a je využíváno záměrně při některých matematických výpočtech.

Pokud je ale uzavřeno do složeného příkazu za příkazem checked volání metody, kontrola přetečení se na tento kód uvnitř volané metody nevztahuje.


Ilustrativní příklad Preteceni
Program Preteceni
  • Popis: Přetečení datového typu integer
  • Zadání: Vytvořte program pro konzolovou aplikaci, ve kterém v hlavní statické metodě Main deklarujete celočíselnou proměnnou horniMez a uložíte do ní největší možné maximální kladné číslo. Hodnotu této proměnné vypište. V následném kroku k této hodnotě přičtěte hodnotu 1 a nechte znovu vypsat hodnotu v proměnné
  • Řešení: Bude postupně probráno v následujícím textu

Následující kód ukazuje, jak využijeme vlastnosti určení maximální hodnoty určitého datového typu. Do proměnné horniMez uložíme tuto hodnotu celočíselného datového typu int – viz Kód 1. Abychom se dozvěděli aktuální hodnotu proměnné, vypíšeme aktuální hodnotu uložené v proměnné pomocí příkazu Console.WriteLine. Abychom dosáhli přetečení (tedy překročení rozsahu daného datového typu), k aktuální hodnotě v proměnné přičteme hodnotu 1. Tento výsledek necháme znovu vypsat.

static void Main(string[] args)
{
    //Deklarace celočíselné proměnné
    int horniMez;
    //Přiřazení hodnoty horní meze int (hodnota 2147483647) do proměnné 
    horniMez = int.MaxValue;
    //Výpis akutální hodnoty proměnné
    Console.WriteLine("Horní mez: {0}", horniMez);
    //Přičtení 1 k aktuální hodnotě v proměnné -> přetečení
    horniMez = horniMez + 1;
    //Výpis akutální hodnoty proměnné
    Console.WriteLine("Horní mez + 1: {0}", horniMez);
    //Čekání na stisk klávesy -> Ukončení programu
    Console.ReadKey();
}

Kód 1: Deklarace hlavní metody Main programu Preteceni - přetečení hodnoty

Na následujícím výpisu programu vidíme, že nejprve byl proveden výpis aktuální hodnoty (horní mez datového typu int, tj. 2147483647) uložené v proměnné horniMez – viz Výstup programu - Kód 1. Co se ale stane, pokud jsme k této hodnotě přičetli 1? Jak vidíte, hodnota se nezvýšila na hodnotu 2147483648, ale spadla na dolní mez datového typu int, tj. -2147483648.

Horní mez: 2147483647
Horní mez + 1: -2147483648

Výstup programu - Kód 1: Ukázka výsledku při přetečení


Ilustrativní příklad KontrolaPreteceni
Program KontrolaPreteceni
  • Popis: Kontrola přetečení datového typu integer
  • Zadání: Modifikujte program Preteceni (viz Kód 1) pro konzolovou aplikaci tak, aby nás kompilátor upozornil na přetečení celočíselné proměnné horniMez 
  • Řešení: Bude postupně probráno v následujícím textu

V následujícím zdrojovém kódu jsme využili klíčového slova checked, abychom si pojistili proti neošetřené výjimce typu OverflowException - přetečení - viz Kód 2. Nebezpečný kód, který je kontrolován horniMez = horniMez + 1;, jsme uzavřeli do složených závorek. 

static void Main(string[] args)
{
    //Deklarace celočíselné proměnné
    int horniMez;
    //Přiřazení hodnoty horní meze int (hodnota 2147483647) do proměnné 
    horniMez = int.MaxValue;
    //Výpis akutální hodnoty proměnné
    Console.WriteLine("Horní mez: {0}", horniMez);
    //Kontrola přetečení
    checked
    {
        //Přičtení 1 k aktuální hodnotě v proměnné -> přetečení
        horniMez = horniMez + 1;
    }            
    //Výpis akutální hodnoty proměnné
    Console.WriteLine("Horní mez + 1: {0}", horniMez);
    //Čekání na stisk klávesy -> Ukončení programu
    Console.ReadKey();
}

Kód 1: Deklarace metody KontrolaPreteceni - Příklad přetečení s použitím checked

Když jsme spustili program, po výpisu horní meze celého čísla jsme byli upozorněni kompilátorem na nepříjemnou skutečnost přetečení prostřednictvím okna s neošetřenou výjimkou - viz Obrázek 1. 

Kontrola přetečení

Obrázek 1: Informace kompilátoru u přetečení

Příkaz checked nebo unchecked lze použít pouze u aritmetických operací prováděných s celými čísly. V naší aplikaci týkající se algoritmu Kalkulacka, bychom mohli využít checked pouze tehdy, pokud bychom používali pouze celočíselné proměnné. Použití u reálných čísel by nevyvolalo výjimku typu OverflowException, o čemž jsme se přesvědčili již v kapitole Ošetření více výjimek, kde jsme narazili na pojem Infinity (nekonečno se znakem ?).