10. előadás (2004. április 20.) A C előfordító (folytatás) Néhány hasznos compiler opció Egy tanulságos könyvtári függvény Változó hosszúságú argumentum lista I/O átirányítás Véletlenszám generálás Parancs végrehajtás 1
A C fordító működésének szemléltetése 2
A C előfordító 16. A parancssorban is adhatunk meg makrót: cc -DLINELENGTH=80 prog.c -o prog Hatása a következő: #define LINELENGTH 80 A #define vagy az #undef felülbírálja a parancssori beállításokat. Érték nélkül is definíálhatunk szimbólumot: cc -DDEBUG prog.c -o prog Ekkor a default érték: 1 Pl. nyomkövetésre jól használható: 3
A C előfordító 17. #ifdef DEBUG printf("Nyomkövetés: Program Verzió:1\n"); #else printf("Program Verzió:1\n"); #endif A program belsejében is használható: x = y *3; #ifdef DEBUG printf("Nyomkövetés:változók (x,y)=\n", x,y); #endif 4
A C előfordító 18. A #error fordító (compiler) hibaüzenetet generál: #ifdef OS_MSDOS #include #elifdef OS_UNIX #include "default.h" #else #error Nem támogatott OS!! #endif 5
A C előfordító 19. Makródefinícióban használható a # stringesítő operátor (string-literal operator), pl.: #define OUT(x) printf(#x) Hívása: OUT(Hello Jani!);-> printf("Hello Jani!"); A speciális karakterekre tekintettel van: OUT("Hello Jani!");-> printf("\"Hello Jani!\""); Makrókifejtéskor két string egyesítésére (konkatenáció) használható a ## konkatenáció operátor (ez nem kezeli az escape karaktereket), pl.: 6
A C előfordító 20. #define SZECSKA(x) func##x salata=SZECSKA(3)(q,w); -> salata=func3(q,w); Módosult a C kód! #include #define OUT(x) printf(#x"egyenlő%d.\n",x) main() { int hossz=123; OUT(hossz); return(0); } printf("hossz""egyenlő%d.\n",hossz); hossz egyenlő
Néhány hasznos compiler opció 1. cc program.c -> a.out -o cc -o program program.c -> program -c cc -c modul1.c modul2.c -> modul1.o, modul2.o cc -o exefajl modul1.o modul2.o -> exefajl -llibrary cc -o calc calc.c -lm (a matematikai könyvtárt explicite kell linkelni) 8
Néhány hasznos compiler opció 2. -Ldirectory cc prog.c -L/home/myname/mylibs mylib.a Különben csak a /lib és /usr/lib helyeken keres. -Ipathname Az include fájlok keresési sorrendje: a forrásfájl helye, az -I -vel megadott katalógusban és végül a /usr/include -ban, pl.: -g Utasítja a compiler-t kiegészítő szimbólum tábla információk készítésére a debug eszközök használatához. 9
Egy tanulságos könyvtári függvény 1. Az stdlib.h -ban található qsort rendező függvény prototípusa: void qsort(void *base, size_t num_elements, size_t element_size, int (*compare)(void const *, void const *)); base : a rendezendő tömbre mutat num_elements : a tömb mérete (elemeinek száma) element_size : a tömb elemeinek mérete byte-okban compare : függvény mutató A qsort azáltal adattípus független, hogy az összehasonlítást a felhasználóra bízza. 10
Egy tanulságos könyvtári függvény 2. A compare függvény egész visszatérő értéke: 0, ha az első érték nagyobb a másodiknál. Pl. rendezzük a következő struktúrát egész kulcsa szerint: typedef struct { int key; struct other_data; } Record; 11
Egy tanulságos könyvtári függvény 3. A compare függyvény definíciója: int record_comp(void const *a,void const *b) { return (((Record *)a)->key -((Record *)b)->key); } Így a qsort hívása pl.: qsort( array, array_length, sizeof(Record), record_comp); 12
Változó hosszúságú argumentum lista 1. Pl.: f(arg1, arg2, utarg,...) Az headerben deklarált függvények és változók: Az egyes argumentumokat egy va_list típusú változóval címezhetjük: va_list ap; A va_start makróval inicializálhatjuk az ap mutatót: va_start (va_list ap, utarg); A va_arg makró megadja a meg nem nevezett következő argumentumot (automatikusan lépteti ap -t): típus va_arg (va_list ap, típus); 13
Változó hosszúságú argumentum lista 2. Az f függvényben az argumentumlista feldolgozása után, de még a visszatérés előtt meg kell hívni a va_end makrót: void va_end (va_list ap); Az int printf (char *formatum,...); pédául így készült. Egy példa (K&R): #include void minprintf (char *fmt,...) { va_list am; 14
Változó hosszúságú argumentum lista 3. char *p, *sert; int iert; double dert; va_start (am, fmt); /* am rááll az első név nélkülire*/ for (p=fmt; *p; p++){ if (*p != '%'){ putchar (*p); continue; } switch (*++p){ case 'd': iert=va_arg(am, int) /*megadja az argumentumot és léptet*/ 15
Változó hosszúságú argumentum lista 4. printf ("%d", iert); break; case 'f': dert= va_arg(am, double); printf ("%f", dert); break; case 's': for (sert=va_arg(am, char *); sert; sert++) putchar (*sert); break; default: putchar (*p); 16
Változó hosszúságú argumentum lista 5. break; }/*switch*/ }/*for*/ va_end (am); /*a lista feldolg. lezárása*/ }/*minprintf*/ 17
I/O átirányítás 1. Bemenet: az int getchar (void) függvény a standard bemenetről olvas egy karaktert, visszatér a beolvasott karakterrel, vagy hiba esetén EOF -fel. prog <állományból (nem kerül az argv -be) pipeing mechanizmussal: masprog | prog (a masprog standard kimenete a prog standard bemenete) 18
I/O átirányítás 2. Kimenet: az int putchar (int) függvény a standard kimenetre ír egy karaktert, visszatér a kiírt karakterrel, vagy hiba esetén EOF -fel. prog >állományba (nem kerül az argv-be) vagy pipeing mechanizmussal: prog | masprog (a prog standard kimenete a masprog standard bemenete) 19
Véletlenszám generálás Az header-ben: int rand (void); 0 <= r <= RAND_MAX 1-ről indul, min. RAND_MAX= void srand (unisgned int start); 0 <= r < 1 #define frand() ((double)rand()/(RAND_MAX +1.0)) 20
Parancs végrehajtás Az -ban int system (const char *s); s az operációs rendszertől függő parancs, pl.: system ("date"); Visszatérési értéke Unix-ban az exit visszatérési értékkel egyezik meg. 21