PB071 Principy nízkoúrovňového programování

Typické chyby v úlohách

Nikto sa nenarodil s klávesnicou v jednej ruke a knihou The C Programming Language od Ritchieho a Kernighana v druhej. Dokonca aj ľudia, čo programujú roky, občas napíšu nepredstaviteľné nezmysly. Táto stránka je venovaná začiatočníckým chybám, ktorým by ste sa mali vyhýbať hlavne v úlohách.

Chýbajúci void nulárnej funkcie

void foo(/* void? */)
{
    // ...
}

Nejde síce o chybu v pravom slova zmysle, ale je potrebné si uvedomiť, že táto funkcia akceptuje ľubovoľný počet ľubovoľných argumentov. Ak ju preto omylom zavoláte napr. foo(2), prekladač sa nebude sťažovať, hoci zrejme od funkcie očakávate iné chovanie, než reálne má. Preto je bezpečnejšie tam void uviesť.

Toto neplatí pre jazyk C++, kde má deklarácia void foo() rovnaký význam ako void foo(void).

Nadbytočné podmienky

if (CONDITION) {
    return true;
} else {
    return false;
}

Táto a jej podobné konštrukcie zbytočne zneprehľadňujú kód. Stačí si uvedomiť, že podmienka v C je logický výraz, hodnotu tohto výrazu teda nie je treba znova testovať, ale môže sa rovno vrátiť:

return CONDITION;
Táto konštrukcia je 1 na stránke hovnokod.cz!

Návratový typ logických funkcií

// funkcia vrati 'y' ak je argument prvocislo, 'n' inak
char isPrime(int x);

// funkcia vrati 8 ak je argument parny, 4 inak
int isEven(int x);

// funkcia vrati cislo z intervalu [0,1) ak je retazec palindrom,
// cislo 3.14159 ak nie a inu hodnotu ak je to procesoru jedno
double isPalindrome(const char* str);

V starších verziách C neexistuje čistý logický typ s dvoma hodnotami. Namiesto neho sa používa int (prípadne iný celočíselný typ) tak, že 0 chápeme ako nepravdivú hodnotu (false) a všetko ostatné ako pravdu (true).

Treba si tiež uvedomiť, že char je tiež číselný typ, pričom znaky ASCII predstavujú svoju číselnú hodnotu (tj. 'a' + 1 == 98 a zároveň 'a' + 1 == 'b', pretože 'b' == 98). Je teda možné použiť char ako logickú hodnotu, ale nedáva zmysel používať y alebo n:

  • namiesto pekného

    if (fun()), if (!fun())

    treba písať

    if (fun() == 'y'), if (fun() == 'n')

  • aký význam majú ostatné znaky?

Čas od času niekto na reprezentovanie logickej hodnoty použije float alebo double. No me gusta.

Od štandardu C99 je možné používať (stále číselný) typ _Bool s hodnotami 0 a 1. Hlavička stdbool.h k tomuto typu zavádza alias bool s hodnotami true a false.

Návratová hodnota funkcie getchar()

#include <stdio.h>

int main(void)
{
    char c;

    while ((c = getchar()) != EOF)
        putchar(c);

    return EXIT_SUCCESS;
}

Vyššie uvedený program sa správa rozumne na takmer všetkých znakoch… okrem znaku s hodnotou \xff, čo je (unsigned char) 255 resp. (signed char) -1.

aisa$ gcc -std=c99 -pedantic -o chars main.c
aisa$ echo -e "abc\xffdef" | ./chars
abc

Program zastal na znaku \xff. Makro EOF má totiž hodnotu (int) -1, ale po zúžení na char v podmienke sa nedá rozoznať od načítaného znaku. Preto getchar() vracaia hodnotu typu int, kde už takýto problém nenastane.

Ak zmeníme riadok 6 na int c, program sa už správa civilizovane:

aisa$ echo -e "abc\xffdef" | ./program
abc?def
Terminál pravdepodobne zobrazí ? namiesto špeciálneho znaku.