Image
8.6.2016 1 Comments

C++ pod lupou - Druhá časť: Tipy súborov

Späť na úvod >> Späť na programovanie >> Späť na seriál

A je za nami ďalší mesiac a my sa opäť stretávame pri ďalšom pokuse preniknúť do tajov C++. Minule som vám uviedol krátky program, predstavujúci zvyčajný úvod do programovania v jazyku C. Azda sa na mňa nikto nenahnevá, že som začal práve ním, hoci náš seriál sa venuje C++. Myslím si totiž, že je úplne zbytočné „vybafnúť“ na vás rovnaký program, ktorý by však naplno využíval črty jazyka C++. Musel by som vám aspoň jemne naznačiť, o čo v ňom ide, a to by som predbiehal výklad.

Mimochodom, pevne dúfam, že sa vám podarilo program úspešne preložiť do spustiteľnej podoby a následne aj spustiť. Žiaľ, nemôžem predvídať všetky problémy, ktoré by potenciálne u vás mohli nastať. V tejto veci vás musím opakovane odkázať na manuály, elektronické príručky a služobne starších programátorov (vo vlastnom záujme v uvedenom poradí, nie každý programátor bude ochotný na vaše - z jeho pohľadu možno otravné otázky - odpovedať).

Takže čo nás teraz čaká? Ako som naznačil minule, budeme sa zaoberať predovšetkým filozofiou vývoja programu v C++. Neľakajte sa, nepôjde o výťah z učebnice softvérového inžinierstva, mám na mysli špecifiká tvorby programu v C++. Opíšeme si, aké rôzne typy súborov sa počas celého procesu môžu (ale aj nemusia) vyskytnúť, a načrtneme celý proces, tak ako obyčajne prebieha.

Typy súborov

Ako v každom inom „vyššom“ programovacom jazyku je aj program v C++ napísaný v človekom čitateľnej (nechcem napísať, že práve najzrozumiteľnejšej) forme, to znamená prakticky vždy v ASCII kóde. To, čo programátor vymyslí a prostredníctvom klávesnice vloží do počítača, sa nazýva zdrojový text (aj zdrojový kód – source code).

Zdrojové súbory

Zdrojový text programu je uložený v obyčajnom textovom súbore (nijaké formátovacie znaky a podobné smeti), ktorý budeme kvôli jednoznačnosti ďalej nazývať zdrojový súbor. Jeho prípona je pre jazyk C (prekvapujúco) .C, pre jazyk C++ je to trošku zložitejšie. V operačných systémoch ako DOS (nie, to nemyslím vážne, DOS nie je operačný systém), Windows a iné (prevažne PC platforma) majú C++ súbory príponu .CPP. Naproti tomu v unixových systémoch sa takmer výhradne dáva prednosť prípone .CC (vlastne .cc, UNIX je case-sensitive). Predpokladám, že väčšina z vás má prístup k bežnému PC, a preto budem ďalej používať príponu .CPP.

Nikde nie je povedané, že program musí byť celý uložený v jedinom zdrojovom súbore. Naopak, z dôvodu intelektuálnej zvládnuteľnosti (a z úcty programátora k svojmu zdravému rozumu) sa väčšie programy rozkladajú do viacerých zdrojových súborov. Ďalším podstatným dôvodom je fakt, že v prípade zmien v programe je efektívnejší preklad menšieho súboru (zahŕňajúceho zmenu) ako neustále prekladanie jedného veľkého a neprehľadného programového súboru.

CPP súbory však nie sú jediné, v ktorých môže byť uložený zdrojový text programov. Ďalším – pre jazyky C a C++ typickým – typom súborov sú tzv. hlavičkové súbory (headerové súbory – header files) s príponou .H alebo v niektorých C++ prekladačoch aj .HPP. Tieto súbory môžu byť (a aj bývajú) pomocou zvláštnej direktívy #include vložené do zdrojových súborov, čo má pri preklade rovnaký dôsledok, akoby ste obsah hlavičkového súboru skopírovali miesto spomenutej direktívy. Výhoda je okamžite zrejmá v prípade, že máme jeden hlavičkový súbor vložený do viacerých zdrojových a opravíme v ňom napríklad nejakú chybu – zmena sa automaticky premietne do všetkých tých súborov, v ktorých je daný header vložený. V opačnom prípade by sme museli prácne rad za radom prechádzať jednotlivé zdrojové súbory a hľadať, kde všade sme napísali ten blud. V praxi sa do hlavičkových súborov vkladajú väčšinou informácie o tom, ktoré funkcie v programe existujú (tzv. prototypy funkcií – dostaneme sa k tomu neskôr), aké spoločné dáta tieto funkcie používajú a pod. Pre tých, čo poznajú Pascal – vloženie hlavičkového súboru v C++ má v hrubých črtoch rovnaký efekt ako použitie klauzuly uses v Pascale - umožňuje však oveľa viac.

Tretím typom súborov, ktorý môže obsahovať zdrojový text, ale ktorý sa nepoužíva tak často, sú súbory, obsahujúce kód písaný priamo v jazyku symbolických inštrukcií (asi pochopiteľnejší názov bude assemblerové súbory). Jazyk C++ je síce mocný, ale nie všemocný a v prípade, že potrebujete napísať superrýchlu funkciu trebárs na vykresľovanie tieňovaných polygónov, rýchlo zistíte, že najvhodnejším riešením bude asi použiť rovno strojový kód.

Medzisúbory

Vopred sa priznávam, že použitý názov medzisúbory (pokus o voľný výklad anglického termínu „intermediate files“) je mojím výmyslom, ale myslím, že dostatočne vystihuje postavenie tohto typu v celkovej hierarchii. Medzisúbory sú akýmsi medziproduktom celého procesu prekladu a pri vývoji programu jedným programátorom od začiatku až do konca si vôbec netreba trápiť hlavu ich existenciou.

Prvým typom medzisúboru je objektový súbor (object file). Na PC obyčajne s príponou .OBJ, v unixe s príponou .o. Tento súbor vznikne prekladom jedného zdrojového súboru (a ním zahrnutých hlavičkových) a obsahuje strojový kód prekladu toho, čo programátor do zdrojového súboru zapísal (a občas aj toho, čo tam nezapísal). Okrem toho obsahuje informácie o tom, čo sa v danom OBJ súbore nachádza (a môže byť použité inými časťami programu), ale aj to, čo sa v ňom nenachádza, no je potrebné na správnu funkciu kódu v tomto súbore (tzv. externé odkazy). OBJ súbor nie je spustiteľný, a to z jednoduchého dôvodu: formát OBJ súboru je iný ako formát EXE súbor. To je vážne najjednoduchší dôvod. Samozrejme, dá sa to vysvetliť aj komplikovanejšie – samostatný OBJ súbor nie je sebestačný, i keď celý program pozostáva z jediného zdrojového súboru. Treba k nemu totiž pribaliť ešte úvodný inicializačný kód, ale na túto tému je trochu priskoro, takže hádam niekedy v budúcnosti.

Druhým typom medzisúboru je tzv. knižničný súbor (knižnica – library file). Tento súbor (na PC s príponou .LIB, v unixe napríklad .a) nie je nič iné ako „zlepenec“ viacerých objektových súborov s definovaným formátom. Aby som bol úprimný, pri bežnom preklade programu sa tento typ vôbec nevyskytuje. No predstavme si situáciu, keď programátor napíše zbierku funkcií, odladí ju a chce ju použiť neskôr v inom projekte, prípadne ju chce poskytnúť svojmu okoliu (programátorskému, samozrejme – asi by nemalo význam ponúkať svojej priateľke či manželke zbierku obľúbených funkcií). Takže čo spraví: preloží potrebné zdrojové súbory do objektových a špeciálnym programom z týchto objektových súborov vytvorí jednu knižnicu (alebo aj viac). Tú následne dôkladne zdokumentuje, pribalí k nej hlavičkové súbory (bez nich je knižnica dosť ťažko použiteľná) a dá na svoju webovú stránku (napríklad).

Výstupné súbory

Množné číslo v nadpise je trochu nadnesené, konečným cieľom celého úsilia sa býva obyčajne jeden súbor – výsledný program. Pravda, to „obyčajne“ platí pre platformu PC, kde existujúce prekladače produkujú takmer výhradne jediný výstupný súbor – klasický EXE súbor, rôzne hybridy typu „overlay“ alebo z prostredia Windows známu DLL knižnicu. V unixe (vďaka faktu, že prakticky všetky prekladače sú ovládané prepínačmi z príkazového riadka a rozumne sa dá pracovať len s pomocou súborov make) je možné jediným príkazom vyprodukovať aj viacero spustiteľných súborov (presnejšie, je možné vyprodukovať ľubovoľné množstvo ľubovoľných súborov, ale o tom sa tu baviť nebudeme).

Pre naše ciele bude azda dostatočne vhodný model vývoja programu, ktorý vytvorí jediný spustiteľný súbor.

Proces prekladu

Teraz, keď už vieme, s akými súbormi máme pri preklade do činenia, môžeme si načrtnúť, ako samotný preklad vyzerá. Tu sú jednotlivé kroky (pozri obr. 1):

1.  Máme vytvorené jednotlivé zdrojové súbory, príslušné hlavičkové súbory a rozhodneme sa spustiť preklad.

2.  Prvým z nástrojov je tzv. preprocesor. Tento program má viacero funkcií, bližšie si o ňom povieme v príslušných častiach nášho seriálu. Zatiaľ vám poviem aspoň toľko, že práve on, má na starosti náhradu direktívy vloženia hlavičkového súboru jeho obsahom. Preprocesor môže existovať ako samostatný program, ale väčšinou býva súčasťou nasledujúceho nástroja.

3.  Ďalším nástrojom je kompilátor. Často sa označuje aj názvom prekladač, to nám však trochu koliduje s pojmom „preklad“ ako proces, ktorý transformuje zdrojové súbory na výstupný súbor. Kompilátor zabezpečuje len jednu fázu tohto prekladu. Kompilátory pre jednotlivé jazyky sa obyčajne líšia, ich výstupom je však zhodne množina objektových súborov. Kompilátor môže byť volaný pre každý zdrojový súbor osobitne alebo dostane ako argument množinu zdrojových súborov, ktoré spracúva po jednom.

4.  Dostali sme objektové súbory, teraz ich treba nejakým spôsobom spojiť. Na to slúži tretí nástroj, tzv. linker (pre jazykových puristov – spojovač). Proces linkovania spočíva jednak v zisťovaní, či každá použitá funkcia či premenná v niektorom objektovom súbore existuje, jednak vo vhodnom pospájaní jednotlivých modulov, pripojení inicializačného kódu a vytvorení daného výstupného súboru.

5.  V prípade, že nechceme vyprodukovať výstupný súbor, ale knižnicu, miesto linkera príde na rad „knihovník“ (ospravedlňujem sa, nenapadá ma vhodnejší preklad pre „librarian“) (pozri obr. 2). Tento knihovník má v podstate podobnú úlohu ako linker, umožní však do knižnice uložiť aj také objektové súbory, ktorým ku šťastiu niečo chýba.

Počas každej fázy prekladu (okrem tej prvej, samozrejme) môže dôjsť, a podľa rôznych programátorských zákonov celkom určite príde, k rôznym chybám. Stručne teraz načrtnem možné okruhy chýb. Medzi chyby preprocesora patrí najčastejšie nemožnosť nájsť príslušný hlavičkový súbor – treba si dať pozor na nastavenie ciest. Chyby kompilátora môžeme rozdeliť na syntaktické (to keď napíšete niečo, čomu kompilátor nerozumie) a sémantické (tie vzniknú vtedy, keď kompilátor síce rozumie tomu, čo ste napísali, rozhodne s tým však nesúhlasí). Linker vás môže tiež zavaliť kôpkou chybových hlásení, z ktorých najčastejším je použitie funkcie, ktorá nikde v programe nie je definovaná.

Štruktúra programu

Prejdeme teraz konečne k tomu, ako taký program v C++ vyzerá a z čoho sa skladá. V prvom rade: jazyk C++ nepozná procedúry, ale iba funkcie. Funkcia je úsek programu s definovaným začiatkom, koncom, počtom a typmi argumentov a typom návratovej hodnoty. Funkciu možno z iného miesta programu zavolať, odovzdať jej prípadné argumenty, tým sa jej odovzdá riadenie a po úspešnom ukončení funkcia tomu, kto ju zavolal, môže vrátiť návratovú hodnotu.

Program v C++ v najjednoduchšom priblížení nie je vlastne nič iné ako množina funkcií, ktoré sa navzájom volajú. Pre tých, ktorým sú známe princípy objektovoorientovaného programovania – aj striktne objektový program je množina funkcií, hoci tieto funkcie sú členmi príslušných tried. Vzhľadom na to, že začíname štúdiom neobjektových čŕt C++, postačí nám takýto pohľad.

Ak sa zamyslíme nad uvedeným modelom programu, rýchlo dospejeme k záveru, že treba určiť, ktorá funkcia dostane slovo ako prvá. V jazyku C++ má toto špecifické postavenie funkcia s názvom main(). Čo sa týka jej argumentov, možno jej odovzdať to, čo za názov programu napíšete na príkazovom riadku, ale k tomu sa ešte dostaneme. Jej návratovou hodnotou môže byť klasický výstupný kód (exit-code; testovateľný napr. v dávkových súboroch DOS-u pomocou premennej ERRORLEVEL). Keď program dospeje ku koncu funkcie main(), skončí sa (samozrejme, pomocou špeciálnych príkazov môže skončiť aj skôr).

Všeobecný (ale zatiaľ zjednodušený) tvar zápisu funkcie vyzerá takto:

 

fnc-typ fnc(arg-typ1 arg1, ... , arg-typn argn)

{

    ... kód funkcie ...

}

 

kde fnc-typ je typ návratovej hodnoty, fnc je meno funkcie, arg-typi je typ argumentui a argi jeho meno.

Ľavá krútená zátvorka označuje začiatok kódu funkcie (ekvivalent pascalovského begin), pravá značí koniec kódu (ekvivalent end) a nepíše sa za ňou bodkočiarka. Medzi týmito dvoma zátvorkami je samotný kód, ktorý funkcia bude vykonávať. Ako si ukážeme v budúcich častiach, tu sa nachádzajú deklarácie premenných, volania iných funkcií, rôzne príkazy a pod.

Jednoduchý, jednosúborový program v C++ obyčajne vyzerá tak, že na začiatku zdrojového súboru sa uvedú hlavičkové súbory, ktoré treba vložiť (pomocou #include), nasledujú definície jednotlivých funkcií a jedna z týchto funkcií má názov main(). Tej sa pri štarte programu odovzdá riadenie a za normálnych okolností jej ukončením sa skončí celý program.

Máte teda predstavu o tom, ako vyzerá hrubá (ale vážne veľmi hrubá!) štruktúra programu v C++. Vzhľadom na to, že vaše doterajšie vedomosti (prosím znalých, aby sa neurazili) nestačia na vytvorenie vlastného programu, opäť mám pre vás na záver jednoduchý program, na základe ktorého by ste mali pochopiť spomínaný model behu programu. Uvedený program sa skladá z troch funkcií, ktoré sa navzájom volajú. Každá z týchto funkcií okrem toho vypíše nejaký text. Na vysvetlenie – printf ("text"); je volanie funkcie (definovanej však mimo nášho programu), ktoré spôsobí výstup daného textu na štandardný výstup. Aby sme túto funkciu mohli používať, treba na začiatku programu vložiť hlavičkový súbor stdio.h. Našu vlastnú funkciu môžeme zavolať tak, že uvedieme jej názov, do zátvorky prípadné argumenty (v našom prípade žiadne) a ukončíme bodkočiarkou.

 

#include <stdio.h>

 

void A()

{

    printf("Hello from function A().");

}

 

void B()

{

    printf("Hello from function B().");

    A();

}

 

void main()

{

    printf("Hello form function main()");

    B();

}

 

Ak si spomínate na predošlý program, tento obsahoval direktívu #include, definíciu funkcie main() a volanie funkcie printf() s argumentom "Hello, world!". Na základe doterajšieho výkladu by vám nemalo robiť problém pochopenie jeho činnosti.

Dovolím si vám dať niečo ako domácu úlohu: vyskúšajte si dnešný program, pokúste sa ho pochopiť a doplniť doň ďalšie funkcie (vypisovať môžu hocičo). Pozor! Volať môžete (zatiaľ) len funkciu, ktorá bola definovaná pred vaším volaním (t. j. v našom príklade funkcia B() môže volať funkciu A(), ale funkcia A() nemôže volať funkciu B()).

Nabudúce

Ak som vás svojím možno ešte stále dosť teoretickým výkladom trochu nudil, nemajte strach – hneď prídu na rad praktické veci. Ak máte pocit, že ste niečomu nerozumeli, napíšte mi a ja vám to (možno) vysvetlím, prípadne počkajte na ďalšie časti – ku všetkému sa dostaneme.

Nabudúce sa budeme zaoberať premennými, ich typmi, základnými operátormi a príkazmi, ako aj základným vstupom a výstupom.

Zobrazit Galériu
C++

Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

Ako na to

Tipy a triky: Ako na snímku obrazovky na akomkoľvek počítači s Windows?

02.12.2016 00:13

Ak snímky obrazovky robíte často apotrebujete napríklad funkcie na posun stránok alebo snímanie zobrazenia pri vyššom rozlíšení displeja, zrejme používate nejakú špecializovanú aplikáciu. Väčšina použ ...

Ako na to 1

Tipy a triky: Ako aplikácii prednastaviť spúšťanie s administrátorskými právami?

30.11.2016 00:10

Väčšina aspoň trochu skúsenejších používateľov vie, že aj keď máte na operačnom systéme Windows vytvorený administrátorský účet, aplikácie pre bezpečnosť nefungujú vždy splnými administrátorskými práv ...

Ako na to 2

Tipy a triky: Ako vypnúť uzamykaciu obrazovku vo Windows 10?

29.11.2016 00:10

Rozčuľuje vás, že pred každým prihlásením doúčtu vášho počítača musíte prejsť uzamykacou obrazovkou? Windows 10 na tejto obrazovke ukazuje čas,dátum anejakú zaujímavú fotografiu zrôznych kútov sveta. ...

1 Comments

  1. chyba reakcia na: C++ pod lupou - Druhá časť: Tipy súborov
    16.11.2016 14:11
    bez return 0 neda funkcia main vediet ze sa korektne ukoncila a takisto je chyba ze neni typu int kedze musi odovzdat cislo 0 na navrat
    Reagovať

Vyhľadávanie

Kyocera - prve-zariadenia-formatu-a4-s-vykonom-a3

Najnovšie videá