Programov´an´ı v C/C++ AUTHOR : Robert Follner DATE Abstrakt ABSTRACT: Nˇekolik poznatk˚ u autora (Robert Follner) z programov´ an´ı v c´eˇcku.
Obsah 1 Jazyk C 1.1 Primitivy jazyka C . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Datov´e typy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Ovl´ad´ an´ı pˇrekladaˇce . . . . . . . . . . . . . . . . . . . . . . . . .
1 1 3 3
2 Pomocn´ e programy 2.1 Instalace Cross-compileru . . . . . . . . . . . . . . . . . . . . . .
3 5
1
Jazyk C
Moje prvn´ı kontakty s programov´ an´ım se odehr´ avaly nˇekdy kolem roku 1986 na skvˇel´em dom´ ac´ım osmibitov´em poˇc´ıtaˇci ZX Spectrum. Asi o dva roky pozdˇeji jsem z´ıskal pˇrekladaˇc jazyka C a moˇzn´ a i C++, ale tuto skvˇelou vlastnost jsem nezkouˇsel. Prvn´ı seriozn´ı pokus o c´eˇckov´ y program se odehr´ al aˇz v roce 1991 s tehdy asi uloupen´ ym pˇrekladaˇcem Turbo C. Po letm´ ych zkuˇsenostech s DOSem a Turbo C jsem byl posazen k nˇejak´ ym historick´ ym stroj˚ um s bl´ıˇze neurˇcen´ ym unixem a samozˇrejmˇe pˇrekladaˇcem jazyka C. Tehdy jsem z´ıskal pˇredstavu, ˇze jazyk C nen´ı takov´a ta modr´ a obrazovka, ale ˇze to spr´ avn´e prostˇred´ı je editor VI a ˇra´dkov´e ovl´ad´ an´ı kompil´ atoru. D´ ale jsem byl sezn´ amen se spoustou nejr˚ uznˇejˇs´ıch parametr˚ u, kter´e je moˇzn´e zadat za pˇr´ıkaz cc a nav´ıc jsem pochopil, ˇze exituj´ı takov´e drobnosti jako preprocesor, vlastn´ı pˇrekladaˇc a linker. Z´akladn´ı knihou se pro mne stala kniha “Operaˇcn´ı syst´em UNIX a jazyk C” autor˚ u Josefa Brodsk´eho a Lud’ka Skoˇcovsk´eho (dˇekuji v´ am, p´ anov´e).
1.1
Primitivy jazyka C
Nadpisem chci vyj´adˇrit, ˇze hodl´ am uv´est seznam pˇr´ıkaz˚ u (kl´ıˇcov´ ych slov) m´eho druh´eho rodn´eho jazyka. 1
auto pamˇet’ov´a tˇr´ıda promˇenn´e break pˇreruˇsen´ı cyklu case vˇetev pˇr´ıkazu switch char celoˇc´ıseln´ y typ promˇenn´e (zpravidla se znam´enkem - tzv. signed ), velikost obvykle jeden bajt const pamˇet’ov´a tˇr´ıda promˇenn´e, jej´ıˇz hodnota nem˚ uˇze b´ yt zmˇenˇena continue pˇreruˇs´ı pr´avˇe prov´ adˇenou smyˇcku cyklu a pokraˇcuje dalˇs´ı iterac´ı default speci´ aln´ı pˇr´ıpad case v pˇr´ıkazu switch, kdy nen´ı nastal´ y stav obslouˇzen ˇza´dn´ ym z pˇredchoz´ıch pˇr´ıpad˚ u case do cyklus, kter´ y se provede nejm´enˇe jednou a b´ yv´ a zpravidla zakonˇcen podm´ınkou pˇr´ıkazu while double else enum extern float for goto if int long register return short sidned sizeof static struct switch
2
typedef union unsigned void volatile while
1.2
Datov´ e typy
Mluv´ıme-li o jazyku C, je sluˇsnost´ı zm´ınit se o datov´ ych typech jazyka a pron´est p´ ar hloup´ ych nar´ aˇzek na typovou kontrolu.
1.3
Ovl´ ad´ an´ı pˇ rekladaˇ ce
Je aˇz s podivem kolik tzv. program´ ator˚ u pouˇz´ıv´ a nejr˚ uznˇejˇs´ı grafick´e nadstavby a jin´e prostˇredky zastiˇ nuj´ıc´ı kr´ asu ovl´ ad´ an´ı jednotliv´ ych pˇr´ıkaz˚ u z pˇr´ıkazov´e ˇr´adky a skript˚ u shellu. Nicm´enˇe, pokud se chce ˇclovˇek spolehnout na sv˚ uj napsan´ y k´od a oˇcek´ avat nav´ıc, ˇze p˚ ujde pˇreloˇzit i na jin´ ych platform´ ach, pak se asi bez znalosti syntaxe souboru Makefile a ovl´ ad´ an´ı pˇrekladaˇce tajemn´ ymi zkratkami neobejde. Je tˇreba zd˚ uraznit, ˇze pˇr´ıkaz cc (nebo gcc) je vlastnˇe jen takov´ y frontend ke tˇrem z´ akladn´ım komponent´ am: 1. preprocesor : obvykle pˇr´ıkaz cp 2. pˇrekladaˇc : obvykle pˇr´ıkaz cc1obj nebo jen cc1 3. linker : obvykle pˇr´ıkaz ld Tyto tˇri programy jsou obvykle vol´ any pˇr´ıkazem cc v uveden´em poˇrad´ı. Jednotliv´e pˇrep´ınaˇce pˇr´ıkazu cc jednak ovlivˇ nuj´ı chov´ an´ı vlastn´ıho pˇr´ıkazu (napˇr. spuˇstˇen´ı pouze preprocesoru: -c), jednak jsou pˇr´ısluˇsn´e pˇrep´ınaˇce pˇred´ any spr´ avn´emu programu (napˇr. -I oznamuje kompil´ atoru, kde m´ a hledat hlaviˇckov´e soubory, nebo -L oznamuje linkeru, kde m´ a hledat soubory knihoven).
2
Pomocn´ e programy
Pˇri programov´ an´ı v jazyku C/C++ se neobejdu bez dalˇs´ıch d˚ uleˇzit´ ych program˚ u. Hlavn´ı n´ apln´ı pr´ace program´ atora nen´ı napsat program, ale opravit v nˇem chyby. Je tedy d˚ uleˇzit´e m´ıt k dispozici program, kter´ y hled´ an´ı chyb usnadn´ı. Ano, h´ ad´ate spr´ avnˇe. Je to debugger - hlavn´ı ladic´ı prostˇredek, kter´ y umoˇzn ˇuje krokov´an´ı programem, sledov´ an´ı promˇenn´ ych, zastavov´ an´ı bˇehu programu, apod. Pouˇz´ıv´am pˇrekladaˇce GNU (gcc) a debugger gdb. Jelikoˇz pracuji v linuxu, tak pouˇz´ıv´am grafickou nadstavbu ddd (the Data Display Debugger).
3
Dalˇs´ı d˚ uleˇzit´a ˇcinnost program´ atora spoˇc´ıv´ a v neust´ al´em hled´ an´ı uˇz jednou napsan´eho k´odu (hrome, kam jsem to dal, jak jsem to jen naprogramoval, jak to bylo? . . . ). Zkuˇsen´ı program´ atoˇri dˇelaj´ı takovou sb´ırku zaj´ımav´ ych funkc´ı, kter´e zpravidla nˇejak tematicky sdruˇzuj´ı. Takov´ a sb´ırka se obvykle naz´ yv´ a knihovna. A na vytvoˇren´ı knihovny je nutno pouˇz´ıt dalˇs´ı programy. Asi hlavn´ı program se jmenuje ar a ten zabal´ı nˇekolik objektov´ ych soubor˚ u (*.o) do souboru knihovn´ıho, kter´ y bude m´ıt koncovku “.lib” nebo jm´eno “libfoo.a”, kde foo je nˇejak´e jm´eno. Zat´ım jsem poznal tˇri druhy soubor˚ u oznaˇcovan´ ych jako knihovny. Prvn´ım a podle m´eho n´azoru nejjednoduˇsˇs´ım typem je statick´ a knihovna “foo.lib” nebo “libfoo.a”. Nejjednoduˇsˇs´ım proto, ˇze na jej´ı v´ yrobu potˇrebuju celkem m´ alo pˇr´ıkaz˚ u. M˚ uj postup je tento: • pˇreklad zdrojov´ ych soubor˚ u do objektov´ ych gcc -c *.c • spojen´ı objektov´ ych soubor˚ u do knihovny ar cr libfoo.a *.o • vytvoˇren´ı indexu objekt˚ u pro rychlejˇs´ı pˇripojov´ an´ı knihovny ranlib libfoo.a Z v´ yˇse uveden´eho je vidˇet, ˇzepˇredpokl´ ad´ am um´ıstˇen´ı vˇsech zdrojov´ ych soubor˚ u do jednoho adres´ aˇre. Pokud jsou v uveden´em adres´ aˇri jeˇstˇe jin´e zdrojov´e soubory, tak je tˇreba je vyjmenovat a nestaˇc´ı jen pouˇz´ıt ˇzol´ıka “*”. Dalˇs´ı druh knihovn´ıho souboru, kter´ y jsem poznal, je sd´ılen´ a dynamick´ a (dynamicky linkovan´a) knihovna. Leckter´ y uˇzivatel produkt˚ u firmy Microsoft si jistˇe vzpomnˇel na sv´e DLL knihovny. Ale nic takov´eho. Nejprve se budu vˇenovat unixu. V´ yrobu dynamick´e (relocatable) knihovny ˇreˇs´ım t´ımto postupem: gcc -O -fPIC -c *.c gcc -W1,-soname,libfoo.1 -shared -v -o libfoo.so.1.1 *.o Zase plat´ı, ˇze knihovnu buduju v propriet´ arn´ım adres´ aˇri. A posledn´ı, mi zn´ am´ y druh knihovny, je ta DLL v MS Windows. Ovˇsem jej´ı vytvoˇren´ı nen´ı tak jednoduch´e, alespoˇ n ne v linuxu. Do linuxu je potˇreba m´ıt nˇejak opatchovanou verzi gcc, ale ta se mi m´ alem nepodaˇrila pˇreloˇzit, protoˇze se to vymlouvalo, ˇze mu chyb´ı nˇejak´e windows-api zdrojov´e soubory a dalˇs´ıch nˇekolik v´ ymluv. Postup vytvoˇren´ı DLL knihovny pomoc´ı GNU pˇrekladaˇce se velmi liˇs´ı podle pouˇzit´e verze a platformy a r˚ uzn´e n´ avody z Internetu zpravidla v nov´ ych verz´ıch nebo jin´ ych portech nefunguj´ı a je tˇreba zkoumat.
4
2.1
Instalace Cross-compileru
Pˇri generov´an´ı DLL knihovny naraz´ıte na spostu probl´em˚ u. Prvn´ım je instalace pˇrekladaˇce. Tady pop´ıˇsu u ´pravy, kter´e bylo nutno uˇcinit pˇri pokusu o nainstalov´an´ı gnu (mingw32) cross kompil´ atoru na linux RedHat 5.2 . Pˇri standardn´ım postupu (vˇcetnˇe ˇcten´ı dokumentace) nastane nˇekolik komplikac´ı. 1. nelze nal´ezt hlaviˇckov´e soubory pro windows32-api 2. pˇreklad gcc skonˇc´ı chybou “nezn´ am´ a platforma” 3. pˇreklad gcc konˇc´ı chybou: ./xgcc -B./ -DIN GCC -g -I./include enquire.o -o enquire ld: cannot open crtbegin.o: No such file or directory 4. pˇri pˇrekladu gcc se nevytvoˇr´ı pˇrekladaˇc pro C++ 5. program dlltool z binutils vol´ a standardn´ı assembler as a nikoliv i386--mingw32-as Standardn´ım postupem je staˇzen´ı a rozbalen´ı tˇechto soubor˚ u (kaˇzd´ y do zvl´ aˇstn´ıho adres´ aˇre): • binutils-2.8.1.tar.gz • gcc-2.7.2.1.tar.gz • mingw32-cpd-0.1.tar.gz • windows32api-0.1.2.tar.gz A pot´e pˇrepnut´ı do adres´ aˇre mingw32-cpd-0.1 a spuˇstˇen´ı skriptu ./Configure a po zodpovˇezen´ı jeho zv´ıdav´ ych ot´ azek n´ asleduje zad´ an´ı pˇr´ıkazu “make install”. Doporuˇcuji vˇsak nejdˇr´ıve udˇelat d´ ale popsan´e u ´pravy, aby se pˇredeˇslo zbyteˇcn´emu b´ad´an´ı, nejasnostem, depres´ım a stresov´ ym stav˚ um. Probl´em ˇc´ıslo jedna jsem si vygeneroval s´ am, protoˇze soubor, kter´ y byl zm´ınˇen na str´ ance toho pˇrekladaˇce byl troˇsku “jin´ y”. Po asi dvou dnech jsem nalezl ten spr´ avn´ y a prvn´ı probl´em t´ım byl odstranˇen. Probl´em ˇc´ıslo dva je zavinˇen t´ım, ˇze star´ a verze gcc nezn´ a platformu i686pc-linux. Pomohla mal´a u ´prava v souboru ./mingw32-cpd-0.1/Configure a sice nˇekde ke konci toho souboru se vol´ a konfigurace gcc t´ımto pˇr´ıkazem: cd $GCC SRC PATH ./configure –target=${TARGET} –with-gnu-as \ –with-gnu-ld –prefix=$PREFIX || fatal ”configure failed” A ten pˇr´ıkaz je nutn´e modifikovat do t´eto podoby:
5
cd $GCC SRC PATH ./configure –build=i486-pc-linux –target=${TARGET} –with-gnuas \ –with-gnu-ld –prefix=$PREFIX || fatal ”configure failed” Tˇret´ı probl´em je mrzut´ y a znamen´ a to, ˇze gcc nen´ı nastaveno jako cross-kompil´ ator. ˇ Ctvrt´ y probl´em lze odstranit u ´pravou souboru Makefile v adres´ aˇri ./mingw32cpd-0.1/ a sice uprav´ıme ˇr´adek ˇc´ıslo 83 (alespoˇ n u mne tomu tak bylo ;-). Jsou tam dva stejn´e ˇr´adky, kter´e vypadaj´ı asi takto: make -C $(GCC SRC PATH) LANGUAGES=”c” A je tˇreba ten druh´ y stejn´ y ˇr´ adek zmˇenit do t´eto podoby: make -C $(GCC SRC PATH) LANGUAGES=”c c++ proto” install A p´at´ y probl´em je tˇreba odstranit u ´pravou zdrojov´eho souboru ./binutils-2.8.1/binutils/dlltool.c, kde je tˇreba zmˇenit ˇr´adek ˇc´ıslo 242, kter´ y definuje jm´eno spouˇstˇen´eho assebleru, takto: char *as name = ”i386–mingw32-as”; Dalˇs´ı probl´em vyvst´ av´a pˇri vlastn´ım linkov´ an´ı knihovny. Zpravidla se setk´ ate s velk´ ym mnoˇzstv´ım hl´aˇsen´ı o nemoˇznosti n´ al´ezt ten nebo onen symbol. Symboly hled´ am pomoc´ı pˇr´ıkazu nm v pˇr´ısluˇsn´e d´ avce: for i in *.a \ do ( echo $i; i386–mingw32-nm $i | grep ’T ’ | grep hledan´ y symbol )\ done | less Hledan´ ym symbolem m˚ uˇze b´ yt napˇr´ıklad token malloc, free, printf apod.
6