Programování v C/C++ AUTHOR : Robert Follner DATE Abstrakt ABSTRACT: Několik poznatků autora (Robert Follner) z programování v céčku. Obsah 1 Jazyk C 1 1.1 Primitivy jazyka C.......................... 1 1.2 Datové typy.............................. 3 1.3 Ovládání překladače......................... 3 2 Pomocné programy 3 2.1 Instalace Cross-compileru...................... 5 1 Jazyk C Moje první kontakty s programováním se odehrávaly někdy kolem roku 1986 na skvělém domácím osmibitovém počítači ZX Spectrum. Asi o dva roky později jsem získal překladač jazyka C a možná i C++, ale tuto skvělou vlastnost jsem nezkoušel. První seriozní pokus o céčkový program se odehrál až v roce 1991 s tehdy asi uloupeným překladačem Turbo C. Po letmých zkušenostech s DOSem a Turbo C jsem byl posazen k nějakým historickým strojům s blíže neurčeným unixem a samozřejmě překladačem jazyka C. Tehdy jsem získal představu, že jazyk C není taková ta modrá obrazovka, ale že to správné prostředí je editor VI a řádkové ovládání kompilátoru. Dále jsem byl seznámen se spoustou nejrůznějších parametrů, které je možné zadat za příkaz cc a navíc jsem pochopil, že exitují takové drobnosti jako preprocesor, vlastní překladač a linker. Základní knihou se pro mne stala kniha Operační systém UNIX a jazyk C autorů Josefa Brodského a Lud ka Skočovského (děkuji vám, pánové). 1.1 Primitivy jazyka C Nadpisem chci vyjádřit, že hodlám uvést seznam příkazů (klíčových slov) mého druhého rodného jazyka. 1
auto pamět ová třída proměnné break přerušení cyklu case větev příkazu switch char celočíselný typ proměnné (zpravidla se znaménkem - tzv. signed), velikost obvykle jeden bajt const pamět ová třída proměnné, jejíž hodnota nemůže být změněna continue přeruší právě prováděnou smyčku cyklu a pokračuje další iterací default speciální případ case v příkazu switch, kdy není nastalý stav obsloužen žádným z předchozích případů case do cyklus, který se provede nejméně jednou a bývá zpravidla zakončen podmínkou pří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é typy Mluvíme-li o jazyku C, je slušností zmínit se o datových typech jazyka a pronést pár hloupých narážek na typovou kontrolu. 1.3 Ovládání překladače Je až s podivem kolik tzv. programátorů používá nejrůznější grafické nadstavby a jiné prostředky zastiňující krásu ovládání jednotlivých příkazů z příkazové řádky a skriptů shellu. Nicméně, pokud se chce člověk spolehnout na svůj napsaný kód a očekávat navíc, že půjde přeložit i na jiných platformách, pak se asi bez znalosti syntaxe souboru Makefile a ovládání překladače tajemnými zkratkami neobejde. Je třeba zdůraznit, že příkaz cc (nebo gcc) je vlastně jen takový frontend ke třem základním komponentám: 1. preprocesor : obvykle příkaz cp 2. překladač : obvykle příkaz cc1obj nebo jen cc1 3. linker : obvykle příkaz ld Tyto tři programy jsou obvykle volány příkazem cc v uvedeném pořadí. Jednotlivé přepínače příkazu cc jednak ovlivňují chování vlastního příkazu (např. spuštění pouze preprocesoru: -c), jednak jsou příslušné přepínače předány správnému programu (např. -I oznamuje kompilátoru, kde má hledat hlavičkové soubory, nebo -L oznamuje linkeru, kde má hledat soubory knihoven). 2 Pomocné programy Při programování v jazyku C/C++ se neobejdu bez dalších důležitých programů. Hlavní náplní práce programátora není napsat program, ale opravit v něm chyby. Je tedy důležité mít k dispozici program, který hledání chyb usnadní. Ano, hádáte správně. Je to debugger - hlavní ladicí prostředek, který umožňuje krokování programem, sledování proměnných, zastavování běhu programu, apod. Používám překladače GNU (gcc) a debugger gdb. Jelikož pracuji v linuxu, tak používám grafickou nadstavbu ddd (the Data Display Debugger). 3
Další důležitá činnost programátora spočívá v neustálém hledání už jednou napsaného kódu (hrome, kam jsem to dal, jak jsem to jen naprogramoval, jak to bylo?... ). Zkušení programátoři dělají takovou sbírku zajímavých funkcí, které zpravidla nějak tematicky sdružují. Taková sbírka se obvykle nazývá knihovna. A na vytvoření knihovny je nutno použít další programy. Asi hlavní program se jmenuje ar a ten zabalí několik objektových souborů (*.o) do souboru knihovního, který bude mít koncovku.lib nebo jméno libfoo.a, kde foo je nějaké jméno. Zatím jsem poznal tři druhy souborů označovaných jako knihovny. Prvním a podle mého názoru nejjednodušším typem je statická knihovna foo.lib nebo libfoo.a. Nejjednodušším proto, že na její výrobu potřebuju celkem málo příkazů. Můj postup je tento: překlad zdrojových souborů do objektových gcc -c *.c spojení objektových souborů do knihovny ar cr libfoo.a *.o vytvoření indexu objektů pro rychlejší připojování knihovny ranlib libfoo.a Z výše uvedeného je vidět, žepředpokládám umístění všech zdrojových souborů do jednoho adresáře. Pokud jsou v uvedeném adresáři ještě jiné zdrojové soubory, tak je třeba je vyjmenovat a nestačí jen použít žolíka *. Další druh knihovního souboru, který jsem poznal, je sdílená dynamická (dynamicky linkovaná) knihovna. Leckterý uživatel produktů firmy Microsoft si jistě vzpomněl na své DLL knihovny. Ale nic takového. Nejprve se budu věnovat unixu. Výrobu dynamické (relocatable) knihovny řeším tímto postupem: gcc -O -fpic -c *.c gcc -W1,-soname,libfoo.1 -shared -v -o libfoo.so.1.1 *.o Zase platí, že knihovnu buduju v proprietárním adresáři. A poslední, mi známý druh knihovny, je ta DLL v MS Windows. Ovšem její vytvoření není tak jednoduché, alespoň ne v linuxu. Do linuxu je potřeba mít nějak opatchovanou verzi gcc, ale ta se mi málem nepodařila přeložit, protože se to vymlouvalo, že mu chybí nějaké windows-api zdrojové soubory a dalších několik výmluv. Postup vytvoření DLL knihovny pomocí GNU překladače se velmi liší podle použité verze a platformy a různé návody z Internetu zpravidla v nových verzích nebo jiných portech nefungují a je třeba zkoumat. 4
2.1 Instalace Cross-compileru Při generování DLL knihovny narazíte na spostu problémů. Prvním je instalace překladače. Tady popíšu úpravy, které bylo nutno učinit při pokusu o nainstalování gnu (mingw32) cross kompilátoru na linux RedHat 5.2. Při standardním postupu (včetně čtení dokumentace) nastane několik komplikací. 1. nelze nalézt hlavičkové soubory pro windows32-api 2. překlad gcc skončí chybou neznámá platforma 3. překlad gcc končí chybou:./xgcc -B./ -DIN GCC -g -I./include enquire.o -o enquire ld: cannot open crtbegin.o: No such file or directory 4. při překladu gcc se nevytvoří překladač pro C++ 5. program dlltool z binutils volá standardní assembler as a nikoliv i386--mingw32-as Standardním postupem je stažení a rozbalení těchto souborů (každý do zvláštního adresáře): 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é přepnutí do adresáře mingw32-cpd-0.1 a spuštění skriptu./configure a po zodpovězení jeho zvídavých otázek následuje zadání příkazu make install. Doporučuji však nejdříve udělat dále popsané úpravy, aby se předešlo zbytečnému bádání, nejasnostem, depresím a stresovým stavům. Problém číslo jedna jsem si vygeneroval sám, protože soubor, který byl zmíněn na stránce toho překladače byl trošku jiný. Po asi dvou dnech jsem nalezl ten správný a první problém tím byl odstraněn. Problém číslo dva je zaviněn tím, že stará verze gcc nezná platformu i686- pc-linux. Pomohla malá úprava v souboru./mingw32-cpd-0.1/configure a sice někde ke konci toho souboru se volá konfigurace gcc tímto příkazem: cd $GCC SRC PATH./configure target=${target} with-gnu-as \ with-gnu-ld prefix=$prefix fatal configure failed A ten příkaz je nutné modifikovat do této podoby: 5
cd $GCC SRC PATH./configure build=i486-pc-linux target=${target} with-gnuas \ with-gnu-ld prefix=$prefix fatal configure failed Třetí problém je mrzutý a znamená to, že gcc není nastaveno jako cross-kompilátor. Čtvrtý problém lze odstranit úpravou souboru Makefile v adresáři./mingw32- cpd-0.1/ a sice upravíme řádek číslo 83 (alespoň u mne tomu tak bylo ;-). Jsou tam dva stejné řádky, které vypadají asi takto: make -C $(GCC SRC PATH) LANGUAGES= c A je třeba ten druhý stejný řádek změnit do této podoby: make -C $(GCC SRC PATH) LANGUAGES= c c++ proto install A pátý problém je třeba odstranit úpravou zdrojového souboru./binutils-2.8.1/binutils/dlltool.c, kde je třeba změnit řádek číslo 242, který definuje jméno spouštěného assebleru, takto: char *as name = i386 mingw32-as ; Další problém vyvstává při vlastním linkování knihovny. Zpravidla se setkáte s velkým množstvím hlášení o nemožnosti nálézt ten nebo onen symbol. Symboly hledám pomocí příkazu nm v příslušné dávce: for i in *.a \ do ( echo $i; i386 mingw32-nm $i grep T grep hledaný symbol ) \ done less Hledaným symbolem může být například token malloc, free, printf apod. 6