субота, 24. октобар 2015.

Obrada grešaka u C++ programskom jeziku

Dok učite programiranje, posebno osnove; retko će te se susretati sa obradom grešaka u vašim programima i to iz opravdanog razloga; da ne biste skretali sa teme. Međutim, kad pravite programe koji nisu ilustracija učenja, morate detaljno da se posvetite sprečavanju grešaka ili da pružite krajnjem korisniku povratnu informaciju da ispravi grešku ukoliko je to moguće. U svakom slučaju ne možete dozvoliti da vam aplikacija padne ili da radi sa netačnim podacima. Ponekad je uočiti, otkriti i ispraviti grešku teži proces nego pisanje sasvim novog koda ili totalnog menjanja pristupa nekom problemu; posebno ako je neko drugi pre vas pisao kod van programerski pravila vaše kompanije. Na projektima se dešava i da nešto što odlično radi samostalno, totalno deformiše celi poslovni proces kad je deo veće celine. Jedno je sigurno, što pre otkrijete i ispravite grešku ona će vas manje koštati. Inače vaš program će biti pun bagovitog i nestabilnog koda, koje će te morati ispravljati kroz update-e i patch-eve. Uvek imajte u vidu da neke programerske greške mogu koštati i ljudske živote. Zato je obrada grešaka prioritet nad prioritetima kod svakog programera. Čak i najmanja struktura koda mora proći kroz detaljna testiranja pre nego što pređu u sledeću fazu projekta.



( Errors, sprečavanje i ispravljanje grešaka je prioritet svakog programera )


Dobra vest je da Microsoft Visual Studio maksimalno olakšava rad sa greškama. Sve vrste grešaka možete podeliti u tri osnovne kategorije:

  • Sintaksne greške
  • Greške programske logike
  • Izuzeci
Sintaksne greške su najlakše, to su greške koje morate da ispravite u svom programskom kodu da biste uspešno kompajlirali program. Greške programske logike, često se zovu i logičke greške; su greške koje otkrivate nakon kompajliranja, izvršavanja i detaljnih testiranja vašeg programa. U kompanijama gde se radi na velikim projektima postoje programeri koji se bave samo testiranjem. Njih zovemo testeri. Njihov posao je najteži i iziskuje ogromno znanje. Oni prave čak programe koje služe samo da testiraju vaš program ili deo programa poput klase. I treća vrsta kategorije grešaka su izuzeci. Oni se često smatraju delom greške programske logike, ali je uvek treba izdvojiti. Izuzecima reagujemo na greške koje se dešavaju tokom izvršavanja. Sa njima će te najviše raditi.

Šta je Code Rot, truljenje koda?


To je izraz, programerska šala; za savršen kod koji se vrati na ispravku. Ponekad i perfektan, dobro napisan i testiran kod tek nakon više meseci posle instaliranja; počinje da proizvodi bizarno ponašanje ali ga ne možete zaustaviti jer je duboko u upotrebi. Tad morate da napišete isti takav vaš program i kad vam se vrati na ispravku da što pre otkrijete u čemu je problem. Zato svaki vaš kod mora biti uvek dobro iskomentarisan jer će te ga verovatno ponovo gledati.

Šta je assert?

Još od programskog jezika C, programeri su često koristili makro-e da urade neke zadatke, što ja ne preporučujem iako sam imao naviku i sam da izmišljam makro-e. Imaju nešto smisla ako programirate u C programskom jeziku. Uglavnom, makro-i sadrže mnogo zagrada; pozivaju se preko #define direktive i sve naredbe u makro-u moraju da stanu u jednu liniju koda. To danas nije praksa i čini kod nečitljivim. Jedan od makro-a koji se pre koristio za proveru parametara; koji vraća TRUE ako parametar ispunjava uslov; su programeri koristili za testiranje koda i zatim taj deo koda uklanjali. Ima i danas starijih programera koji koriste assert() za testiranja ali je to retkost. Pogledajte ovaj primer:

#include "stdafx.h"
#include <iostream>
#include <assert.h>
using namespace std;

void test(char *, int);

int main()
{
       char *string = "Some string";
       int number = 8;

       test(string, number);
       printf("The string ' %s ' is not null or empty\n"
             "and number %d is bigger than zero.\n"
             "The test is passed!\n\n", string, number);

       system("PAUSE");
       return 0;

}

void test(char *string, int number)
{
       assert(string != NULL);
       assert(*string != '\0');
       assert(number > 0);

}

Ukoliko pokrenete program, test funkcija će da proveri vaše promenjive. Samo ukoliko se od svih assert-a vrati TRUE, vaše promenjive će proći test.

The string ' Some string ' is not null or empty
and number 8 is bigger than zero.
The test is passed!

Press any key to continue . . .


Kako izgleda program možete videti i na video-u:


 

( C++ Tutorial - 13. Asserts )

Međutim ako se pojavi greška, izvršavanje programa će biti prekinuto. Pogledajte sliku ako promenjiva number ima vrednost 0 i kad assert vrati FALSE.



( Upotrebom Assert-a prekidate rad programa kad naiđe na grešku )

I sami možete videti da assert poziva abort programa. To nije isto kao i kad vam padne program. Danas se za hvatanje grešaka koriste Try Catch blokovi.


Šta je Try Catch blok, kad i kako se koristi?

Kad su u pitanju greške vi će te lako rešavati sintaksne greške jer vaš IDE će hvatati takve greške, u vašem kodu i podvući će ih crvenom cik cak linijom i neće vam dozvoliti da kompajlirate program dok tu grešku ne ispravite. Microsoft Visual Studio je specifičan po tome što će vam opisati problem u tool tip-u koji se aktivira na mestu gde se pojavi navedena linija. Takođe će vam ponuditi i rešenje i drugu pomoć. Kod logičkih grešaka, vi uMicrosoft Visual Studio imate mogućnost da pravite break point-e – tačke prekida i da zaustavite program na takvim tačkama i pratite tok izvršavanja aplikacije do kraja. Istovremeno vama se nude i drugi prozori gde možete pratiti vrednosti vaših promenjivih, output i dijagnostiku. Ali logičke greške je najteže otkriti i samo sa zdravim i iskusnim logičkim razumom i što opširnijim testiranjima možete rešiti i takvu vrstu grešaka iako je nemoguće sve predvideti.


( Visual Studio 2015 Tools, pomoć za otkrivanje logičkih grešaka )

Međutim, izuzeci; ili greške koje se pojavljuju prilikom izvršavanja vaše aplikacije rešavate try catch block-om jer imate potrebu da se prekine izvršavanje vašeg programa, kako bi ste mogli da reagujete. Na taj način vi ćete presresti greške poput pokušaja deljenja nulom, upotrebu null pokazivača u izrazu koji zahteva važeća adresa, neuspešno dodeljivanje zahtevne memorije, kad je memorija popunjena, aritmetičko prekoračenje prilikom izračunavanja i mnogo drugih. Sve su to greške koje vi programerski rešavate upravo u try catch block-u. Za C# programere mogu samo napomenuti da try catch block u C++ programskom jeziku nije jednostavno koristiti kao u C# programskom jeziku. Kako se najjednostavnije koristi try catch block, najbolje pogledajte u ovom primeru. Obratite pažnju na naredbu throw; ona ispaljuje i određuje koji tip će imati izuzetak.

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

short division(short a, short b)
{
       if (b == 0)
       {
             throw "Division by zero condition!";
       }
       return (a / b);
}

int main()
{
       short number1, number2;

       cout << "Input number 1: ";
       cin >> number1;

       cout << "Input number 2: ";
       cin >> number2;
            
       try
       {
             division(number1, number2);
             cout << endl << number1 << " / " << number2 << " = " << (number1 / number2) << endl << endl;

       }
       catch (const char* msg)
       {
             cerr << endl << msg << endl << endl;

       }

       system("PAUSE");
       return 0;

}

Kako to sve izgleda možete pogledati i na video-u:


( C++ Tutorial - 14. Try Catch Block )