Programování pro PalmOS počítače krok za krokem (62)

Dnes si povíme o různých chybách, které mohou nastat při běhu programu, a o způsobech, jak se s nimi vypořádat.

5.4. Informování programátora a uživatele o chybě

Zatímco u stolních počítačů si uživatelé na častou nutnost restartovat operační systém již zvykli, u přenosných zařízení, jako jsou PDA a mobilní telefony, očekávají dlouhodobou spolehlivost a bezpečnost dat. Proto musíme již při návrhu našich aplikací předcházet chybám, které by mohly ovlivnit důvěru uživatele v naši aplikaci a v mobilní zařízení obecně.

Při psaní aplikace mohou nastat tři druhy chyb. První z nich jsou chyby programátora. Příkladem těchto chyb je záměna identifikátoru políčka pro editaci textu a tlačítka, použití špatné proměnné pro uložení výsledku nebo třeba špatná kombinace parametrů a textu výzvy u funkce FrmCustomAlert(). Tyto chyby se často označují za chyby interní a vedou ke špatné funkci programu, nebo přímo k fatální chybě operačního systému PalmOS a nutnosti restartovat počítač.

Druhá skupina chyb reaguje na nečekané události při běhu programu, například na nedostatek paměti. Tyto chyby se vyskytují nepravidelně a nejsou-li ošetřeny, vedou k neočekávaným zhroucením aplikace. Nečekané události je možné předvídat, a například po každém požadavku na větší blok paměti kontrolovat, zda byl doopravdy vytvořen. Pokud k nečekané události dojde, měla by aplikace co nejrychleji skončit a to i za cenu nutnosti restartovat operační systém.

Třetím druhem chyb jsou chyby uživatele. Uvedené tři skupiny se od sebe liší zejména tím, jak a kdy je nutno je obsloužit. Rozebereme si krátce všechny tři druhy chyb a uvedeme možnosti jejich ošetření.

Chyby programátora

Při psaní programů se může lehce stát, že spleteme jména dvou proměnných, dvou konstant, špatně uzávorkujeme výraz nebo blok kódu. Výsledkem je, že program dělá něco jiného, než jsme původně očekávali. Hledáním podobné chyby v programu můžeme strávit dlouhé hodiny; chybová hlášení operačního systému PalmOS neoplývají informacemi, které by nám v ladění pomáhaly.

Proto je vhodné vkládat na klíčová místa programu kontrolní bloky, které slouží k ověření povolených hodnot proměnných, parametrů funkcí a podobně. V jazyce C/C++ pro tento druh kontrol existuje makro assert(). Hlavičkové soubory operačního systému PalmOS obsahují podobná makra, která můžeme v našich programech použít.

ErrNonFatalDisplayIf(podmínka, text)
ErrFatalDisplayIf(podmínka, text)

Makra testují výraz a pokud je nenulový, zobrazí chybové hlášení. Závisí na definici ERROR_CHECK_LEVEL.

Vstupní parametry
  • podmínka - testovaný výraz
  • text - hlášení o chybě, které je zobrazeno, má-li podmínka nenulovou hodnotu

Makra ErrNonFatalDisplayIf() a ErrFatalDisplayIf() se od sebe liší tím, že druhé z nich po zobrazení chybového hlášení restartuje operační systém. Makro ErrNonFatalDisplayIf() používáme pro méně závažné chyby, které dovolují pokračovat v provádění programu.

Chceme-li použít makra ErrNonFatalDisplayIf() a ErrFatalDisplayIf() v naší aplikaci, musíme před vložením hlavičkového souboru PalmOS.h nebo v souboru Makefile definovat konstantu ERROR_CHECK_LEVEL podle následující tabulky:

  Funkce ErrNonFatalDisplayIf() Funkce ErrFatalDisplayIf()
#undef ERROR_CHECK_LEVEL
ignorována ignorována
#define ERROR_CHECK_LEVEL ERROR_CHECK_PARTIAL
ignorována zobrazí chybovou hlášku a restartuje operační systém
#define ERROR_CHECK_LEVEL ERROR_CHECK_FULL
zobrazí chybovou hlášku a umožní pokračovat v provádění aplikace zobrazí chybovou hlášku a restartuje operační systém

Příklad použití funkce ErrFatalDisplayIf() je v následujícím rámečku. Změníme-li později definici na prvním řádku tak, že konstanta ERROR_CHECK_LEVEL nebude definována, nebude výsledná aplikace obsahovat kontroly chyb a výsledný soubor *.prc bude menší.

#define ERROR_CHECK_LEVEL ERROR_CHECK_FULL
#include 

...

void UlozText(Char* text)
{
   Char buf[100];

   ErrFatalDisplayIf(!text, "špatná hodnota parametru funkce UlozText()");
   ErrFatalDisplayIf(StrLen(text) > 100, "UlozText(): příliš dlouhý text");

   StrCopy(buf, text);
   ...   
}

Nemusíme se omezovat na makra definovaná v hlavičkových souborech PalmOS. Každý z vás je už jistě schopen naprogramovat podobné makro ohlašující chybu: například pomocí volání funkce FrmCustomAlert(), o které jsme psali v předchozím dílu.

Neočekávané situace v programu

Při běhu naší aplikace na počítači PalmOS musíme počítat s nejrůznějšími neočekávanými komplikacemi, které by mohly ovlivnit chování programu. Nedostatek paměti, nenalezená databáze nebo spuštění pod jinou verzí PalmOS, než kterou naše aplikace očekává, jsou jenom příklady problémů, se kterými se při běhu může náš program setkat.

Volání řady funkcí operačního systému PalmOS může skončit neúspěchem. Funkce, které mohou (z libovolného důvodu) selhat, se dělí do dvou skupin:

  • Funkce, které v případě selhání vrátí nesmyslnou hodnotu (například funkce MemPtrNew() vrátí v případě selhání hodnotu NULL).
  • Funkce, které vracejí nebo ukládají do proměnné kód chyby.

U první skupiny funkcí musíme v naší aplikaci pečlivě hlídat návratové hodnoty. Pokud k neočekávané situaci dojde, musíme ji přiměřeně řešit. V případě nedostatku paměti můžeme ukončit funkci nebo aplikaci; dojde-li k chybě, kterou můžeme napravit, napravíme-ji.

Boolean Testuj(Char* testovane)
{
    Char* pole = (Char*)MemPtrNew(1000);

    if(!pole)
    {
        return false;
    }

    StrCopy(pole, testovane);

    ...

    MemPtrFree((MemPtr)pole);

    return true;
}

K uložení čísla chyby se v operačním systému PalmOS používá 16bitový datový typ Err. Hodnota errNone znamená, že funkce pracovala bez chyb; ostatní hodnoty reprezentují číslo chyby. Každá součást operačního systému PalmOS (správce paměti, databáze) používá vlastní jedinečná čísla chyb.


Příště dokončíme povídání o chybách popisem chyb, které způsobuje uživatel, a začneme popis definice a ovládání seznamů.