10. Preprocesor II
  1. Preprocesor umožňuje provádět také podmíněný překlad částí zdrojového kódu programu. Podmíněné direktivy (#if, #ifdef, #ifndef, #else, #elif a #endif) určují, která část textu zdrojového programu bude překládána. Nejdůležitější použití těchto direktiv je zajištění překladu správných částí programu v případě, kdy program je určen pro několik různých prostředí (např. pro DOS nebo Windows) nebo v případě, kdy zdrojový text bude používán v programu zapsaném v jazyku C nebo C++ (např. jeden hlavičkový soubor budeme někdy používat v C a jindy v C++). Můžeme je také použít k zajištění toho, aby jeden hlavičkový soubor nebyl do jednoho programu vložen vícekrát.

  2. Na tuto poslední možnost se podíváme podrobněji. Když se podíváme na prázdný hlavičkový soubor nějakého formuláře (začneme s vývojem nové aplikace GUI, přejdeme do editoru kódu a v místní nabídce editoru zvolíme Open Source/Header File) pak vidíme tento text:
    //---------------------------------------------------------------------------
    #ifndef Unit1H        // zjištění, zda je definován symbol Unit1H
    #define Unit1H        // definice symbolu Unit1H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    //---------------------------------------------------------------------------
    class TForm1 : public TForm
    {
    __published: // IDE-managed Components
    private: // User declarations
    public:  // User declarations
        __fastcall TForm1(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif                // konec podmíněného překladu
    V tomto textu je zajištěno, aby nemohl být podruhé vložen hlavičkový soubor do stejného programu (pomocí deklarace symbolu - makra odpovídajícího jménu souboru). Pokuste se pochopit jak použité direktivy pracují.
  3. Direktiva #pragma umožňuje zavádět direktivy specifické pro danou implementaci (různé překladače mohou mít různé direktivy). Direktiva, která není v daném překladači podporována je překladačem ignorována.

  4. Pokud si prohlédneme některý z již vytvořených programů, pak nalezneme direktivu
    #pragma hdrstop
    Tato direktiva ukončuje seznam hlavičkových souborů, které budou předpřeloženy. Před touto direktivou jsou vkládány hlavičkové soubory, které se nemění a je tedy možno je přeložit pouze jednou. Tím je možno zkrátit dobu dalších překladů aplikace.
    C++ Builder definuje ještě několik takovýchto direktiv.
  5. Hlavičkový soubor math.h obsahuje definice různých matematických funkcí. Jsou zde např. definovány funkce: acos (arkus kosinus), asin (arkus sinus), atan (arkus tangens), ceil (zaokrouhlování nahoru), cos (kosinus), cosh (hyperbolický kosinus), exp (exponenciální funkce), floor (zaokrouhlování dolu), log (přirozený logaritmus), log10 (dekadický logaritmus), poly (hodnota polynomu), pow (xy), sin (sinus), sinh (hyperbolický sinus), sqrt (druhá odmocnina), tan (tangens) a tanh (hyperbolický tangens).Pomocí nápovědy se seznamte např. s funkcí pow. Vyzkoušejte si vzorový příklad z nápovědy.
  6. Následující konzolová aplikace ukazuje použití parametrů funkce main k předávání parametrů příkazového řádku. Vyzkoušejte ji s různými parametry. V integrovaném prostředí C++ Builderu můžeme parametry příkazového řádku zadávat v dialogovém okně zobrazeném po volbě Run | Parameters. Co určuje parametr s indexem 0? Jak je nutno zadávat parametry obsahující mezery?

  7. int main(int argc, char **argv)
    {
      int i;
      cout << argc << endl;
      for (i = 0; i < argc; i++)
        cout << "Parametr " << i << ": " << argv[i] << endl;
      getch();
      return 0;
    }
  8. Následující konzolová aplikace obsahuje funkci kopírující znaky z klávesnice na obrazovku a počítající jejich počet. Ukončující znak je znak tečky. Je to první program, ve kterém jsme vytvořili svoji funkci (více o deklaracích a definicích funkcí se dozvíme v následující kapitole).

  9. int copy(void)
    {
      char c;
      int pocet = 0;
      while ((c = getchar()) != '.') {
        cout << c;
        pocet++;
      }
      cout << c;       // vypíše se tečka
      cout << endl;
      return pocet;
    }

    int main(int argc, char **argv)
    {
      cout << "Napiš větu ukončenou tečkou:" << endl;
      cout << "Počet znaků = " << copy() << endl;
      getch();
      return 0;
    }
    Program vyzkoušejte. Upravte funkci copy tak, aby (mimo kopírování znaků) počítala pouze znaky mezer.


  10. Pomocí voleb Run | Trace Into a Run | Step Over můžeme provádět náš program po jednotlivých řádcích. Vyzkoušejte. Pokuste se zjistit jaký je rozdíl mezi těmito volbami. Pomocí těchto voleb (trasování programu) můžeme zjistit, zda příkazy programu se provádějí v tom pořadí, ve kterém očekáváme.
  11. Trasování programu nám může pomoci při ladění programů (zjišťování, zda program pracuje správně). Další pomocí by bylo, kdybychom si mohli zjistit hodnoty některých proměnných a mohli sledovat, zda tyto hodnoty se správně mění. Toto můžeme snadno provést. Volbou Run | Add Watch přidáme do sledovacího okna proměnné, které nás zajímají a při trasování programu se ve sledovacím okně tyto proměnné zobrazují i s jejich aktuálními hodnotami. Vyzkoušejte pro předchozí konzolovou aplikaci pro proměnné c a pocet.

Nové pojmy:

10. Preprocesor II