Programozás I. Széchenyi István Egyetem, Gy r 2013. október 16.
feladatai Emlékeztet : forrásfájl (el feldolgozó fordító) kapcsoló-szerkeszt futtatható állomány tevékenységei: kifejti a makrókat (dene) fájlokat szerkeszt be (include) lehet vé teszi a feltételes fordítást egyesíti a szomszédos karakterlánc konstansokat elhagyja a neki szóló direktívákat a megjegyzéseket egyetlen szóközzel helyettesíti egymást követ fehér karaktereket egy darabbal helyettesíti (kivéve karakter és karakterlánc konstansokban)
Direktívák írásszabálya a sor els (nem fehér) karaktere # ezt követhetik fehér karakterek (kivéve újsor) a karakter és -lánc konstansban lév # nem egy új direktíva kezdete a direktívákat nem szabad ;-vel zárni! újsor el tti \ karakter: folytatássor direktívába megjegyzés írható forrásszövegben bárhol elhelyezhet ek, de csak az azt követ részre hatnak
Direktívák üres, include Üres (null) direktíva egyetlen # karaktert tartalmazó sor elhagyja, hatástalan include direktíva fájl tartalmának beszerkesztése, alakjai: #include <fájlazonosító> újsor fejleszt környezetben megadott könyvtárban keresi #include "fájlazonosító" újsor az expliciten adott könyvtárban, annak hiányában pedig az aktuális könyvtárban keresi A fájlazonosító belsejében sincs makróhelyettesítés de a teljes fájlazonosítót megadhatjuk makróval ha >, ", ', \ vagy /* karakterek vannak deniálatlan viselkedés több szinten egymásba ágyazhatóak (fejleszt környezet korlátozhatja a mélységet)
Direktívák include inc1.c #define FAJL "csajok.h" #include FAJL int main(void) { printf("átlagéletkor: %d\n", KOR); return 0; } csajok.h #include<stdio.h> #define KOR 19
Direktívák define Makródeníciók egyszer függvényszer (formális paraméterlista) Egyszer makrók alakja: #define azonosító <el feldolgozó-szimbólumok> újsor el feldolgozó-szimbólumok makrótest el feldolgozó-szimbólumok cseréje a makrótestre: makrókifejtés a makró akkor is deniált, ha nincsenek el feldolgozó-szimbólumok (ld. pl. #ifdef) azonosító törlése a forrásból csak tökéletesen egyez módon deniálható újra (értelmetlen) vagy deniálatlanná tételt (ld. #undef) követ en makrók egymásba ágyazhatók akár nyelvi kulcsszavak is lehetnek az <el feldolgozó-szimbólumok> között, de védett és szabványos, el redeniált makrók azonosítói nem!
Direktívák define makro.c #include<stdio.h> #define EGESZ int #define NYOMTAT putchar #undef NYOMTAT #define NYOMTAT printf #define NYOMTAT printf #define CIKLUS ELOLTESZT #define ELOLTESZT for #define BEGIN { #define END } #define URES int main(void) BEGIN EGESZ i; NYOMTAT("Számok négyzetei\n\n"); URES CIKLUS(i=1; i<=10; i++) BEGIN NYOMTAT("%d^2=%d\n", i, i*i); END URES return 0; END
El redeniált makrók Tulajdonságaik: az el feldolgozás kezdetének pillanatától deniáltak nem tehet k deniálatlanná nem deniálhatók újra Szabványos, el redeniált makrók és jelentésük: DATE aktuális forrás el feldolgozása megkezdésének dátuma HHH NN ÉÉ formátumban FILE forrásfájl azonosítója, megváltozhat: #include és #line direktívák hatására fájl végére érve LINE forrásfájl aktuális sora, értékét módosíthatja pl. #line direktíva STDC csak akkor deniált 1 értékkel, ha ANSI kompatibilis fordítás zajlik TIME aktuális forrás el feldolgozása megkezdésének id pontja OO:PP:MM formátumban
El redeniált makrók elodef.c #include<stdio.h> int main(void) { printf("aktuális forrásfájl: %s\n" "El feldolgozás megkezdésének dátuma: %s, id pontja: %s\n" "Aktuális sor: %d\n", FILE, DATE, TIME, LINE ); #ifdef STDC printf("ansi kompatibilis C fordítás történik.\n"); #endif return 0; } Kimenet Aktuális forrásfájl: elodef.c El feldolgozás megkezdésének dátuma: Oct 16 2013, id pontja: 11:04:34 Aktuális sor: 6 ANSI kompatibilis C fordítás történik.
Direktívák undef, paraméteres define Makró deniálatlanná tétele alakja: #undef azonosító újsor nem deniált azonosító -ra is kiadható Paraméteres define alakja: #define azonosító(azonosítólista) el feldolgozó-szimbólumok újsor az azonosító és a ( közé nem kerülhet fehér karakter! egyszer makró függvényszer makrók, formális paraméterlista el ny: nincs fv. hívási id gyorsabb programok hátrány: n a program mérete (kódismétlést okoz) csak egyszer, de sokszor használt tevékenységekhez ajánlott
Direktívák paraméteres define Probléma: a paraméter egy kifejezés m veleti sorrend #include<stdio.h> #define SQR(n) n*n int main(void) { printf("%d négyzete: %d\n", 3, SQR(3)); /* 3 négyzete: 9 */ printf("%d négyzete: %d\n", 3+1, SQR(3+1)); /* 4 négyzete: 7 */ #undef SQR #define SQR(n) (n)*(n) printf("%d négyzete: %d\n", 3+1, SQR(3+1)); /* 4 négyzete: 16 */ return 0; } Probléma: makró kifejezésben m veleti sorrend #include<stdio.h> #define ADD(a,b) (a)+(b) int main(void) { printf("1+2=%d\n", ADD(1, 2)); /* 1+2=3 */ printf("4*1+2=%d\n", 4*ADD(1, 2)); /* 4*1+2=6 */ printf("4*(1+2)=%d\n", 4*(ADD(1, 2))); /* 4*(1+2)=12 */ #undef ADD #define ADD(a,b) ((a)+(b)) printf("4*(1+2)=%d\n", 4*ADD(1, 2)); /* 4*(1+2)=12 */ return 0; }
Direktívák paraméteres define Néhány további tulajdonság: a makró nem függvény, tehát nem kerül sor a paraméterek típusának ellen rzésére az aktuális paraméterekben szerepl vessz k nem min sülnek elválasztónak, ha zárójelben, idéz jelek vagy aposztrófok között helyezkednek el paraméterként átadott kifejezés kiértékelése többször is megtörténik (id, mellékhatások) két szimbólumot (tokent) összef zve egy harmadikat állít el a ## a formális paraméter elé írt # karakterláncot állít el a paraméterb l (körbeveszi idéz jelekkel) most is lehet folytatássort készíteni az újsor el tti \-sel
Direktívák paraméteres define feldef.c #include<stdio.h> #define ADD(a,b) ((a)+(b)) #define SQR(n) ((n)*(n)) #define ERR(kod, uzenet) printf("hibakód: %d, \ hibaüzenet: %s\n", kod, uzenet) #define VARS(n,v) int i##n = v; char c##n = v; #define PRINT(n) printf(#n " értéke: %d\n", n) int main(void) { VARS(valtozo, 3) PRINT(cvaltozo); PRINT(ivaltozo); printf("ivaltozo négyzete: %d\n", SQR(ivaltozo++)); PRINT(ivaltozo); printf("1+2+3+4=%d\n", ADD(ADD(1, 2), ADD(3, 4))); ERR(3, "I/O hiba, vagy a lemez megtelt"); return 0; } Kimenet cvaltozo értéke: 3 ivaltozo értéke: 3 ivaltozo négyzete: 9 ivaltozo értéke: 5 1+2+3+4=10 Hibakód: 3, hibaüzenet: I/O hiba, vagy a lemez megtelt
Karakterek vizsgálata, átalakítása sok rendszerben függvényszer makrókkal oldják meg ctype.h bekapcsolása szükséges Paraméter típusa int, de az értéknek unsigned char-ral ábrázolhatónak, vagy EOF-nak kell lennie Visszatérési érték int, karakterosztályozó rutinoknál logikai értékként kezelend Fv./makró név islower(c) isupper(c) isalpha(c) isdigit(c) isalnum(c) isxdigit(c) isspace(c) isprint(c) tolower(c) toupper(c) Funkció c kisbet? c nagybet? islower(c) isupper(c) c számjegy? isalpha(c) isdigit(c) c hexadecimális számjegy? c fehér karakter? c nyomtatható? c kisbet s alakja, ha c nagybet c nagybet s alakja, ha c kisbet
Karakterek vizsgálata, átalakítása Lehetséges megvalósítás /* Bitmaszk értékek a lehetséges karaktertípusokra: */ #define _UPPER 0x1 /* Nagybet. */ #define _LOWER 0x2 /* Kisbet. */ #define _DIGIT 0x4 /* Decimális számjegy. */ #define _SPACE 0x8 /* '\t','\r','\n','\v','\f' */ #define _PUNCT 0x10 /* Elválasztó-jel. */ #define _CONTROL 0x20 /* Vezérl karakter. */ #define _BLANK 0x40 /* Szóköz. */ #define _HEX 0x80 /* Hexadecimális számjegy. */ /* Globális tömb, melyben a rendszer mindenegyes kódtábla pozícióra beállította ezeket a biteket: */ extern unsigned char _ctype[]; /* Néhány makró: */ #define islower(_c) (_ctype[_c]&_lower) #define isupper(_c) (_ctype[_c]&_upper) #define isalpha(_c) (_ctype[_c]&(_upper _LOWER)) #define isdigit(_c) (_ctype[_c]&_digit) #define isalnum(_c) (_ctype[_c]&(_upper _LOWER _DIGIT)) #define isxdigit(_c) (_ctype[_c]&_hex) #define isspace(_c) (_ctype[_c]&(_space _BLANK)) #define isprint(_c) (_ctype[_c]&(_blank _PUNCT _UPPER _LOWER _DIGIT))
Karakterek vizsgálata, átalakítása pelda19.c /* PELDA19.C: A bemenet karaktereinek leszámlálása kategóriánként az is... függvények segítségével. */ #include <stdio.h> #include <ctype.h> void main(void){ short k, num=0, feher=0, egyeb=0; printf("bemeneti karakterek leszámlálása\n" "kategóriánként EOF-ig, vagy Ctrl+Z-ig.\n"); while((k=getchar())!= EOF) if(isdigit(k)) ++num; else if(isspace(k)) ++feher; else ++egyeb; printf("karakter számok:\n----------------\n" "numerikus: %5hd\nfehér: %5hd\n" "egyéb: %5hd\n----------------\n" "össz: %10ld\n", num, feher, egyeb, (long)num+feher+egyeb); }
Direktívák paraméteres define Mi történik, ha egyezik egy függvény és egy makró neve? el feldolgozás megel zi a fordítást makró használatával próbálkozik fv. nevét zárójelpárba téve biztosan a függvény hívása történik meg makrót deniálatlanná lehet tenni #undef direktívával nevutkozes.c #include<stdio.h> #define A 2 #define B 5 #define max(a,b) ((a)>(b)?(a):(b)) int (max)(int a, int b) { printf("függvény szerint: "); return a>b?a:b; } int main(void) { printf("%d és %d közül %d a nagyobb.\n", A, B, max(a, B)); printf("%d és %d közül %d a nagyobb.\n", A, B, (max)(a, B)); #undef max printf("%d és %d közül %d a nagyobb.\n", A, B, max(a, B)); return 0; } Kimenet 2 és 5 közül 5 a nagyobb. függvény szerint: 2 és 5 közül 5 a nagyobb. függvény szerint: 2 és 5 közül 5 a nagyobb.
Feltételes fordítás alakja: #if konstans-kifejezés1 <szekció1 > <#elif konstans-kifejezés2 <szekció2 >> /*... */ <#elif konstans-kifejezésn <szekción >> <#else <végs -szekció >> #endif célja: feltételekt l függ en csak bizonyos programrészek megtartása/törlése a konstans-kifejezés -ek típusa logikai korlátozott, egész típusú kifejezés (el feldolgozó értékeli ki): karakter és egész állandókat, defined operátort tartalmazhat, de pl. lebeg pontos konstanst, sizeof operátort, explicit típuskonverziót nem! az #if #endif szerkezetek tetsz leges mélységben egymásba ágyazhatók
Feltételes fordítás A defined operátor fej.h célja: makrók deniáltságát ellen rzi alakjai: defined(azonosító) defined azonosító válasz: logikai, és logikai operátorokkal együtt használható alkalmazása: pl. biztosítja, hogy egy fejfájl egyszer kerülhessen csak beépítésre #if!defined(_fej) #define _FEJ /* érdemi tartalom */ #endif
Direktívák #ifdef, #ifndef, #line, #error,... Az #ifdef, #ifndef direktívák céljuk: makró deniáltságát/deniálatlanságát ellen rzik #if defined(azonosító) #ifdef azonosító #if!defined(azonosító) #ifndef azonosító A #line direktíva célja: expliciten állítani FILE és LINE makrók értékét alakja: #line egész-konstans <"fájlazonosító"> újsor fájlazonosító -t elhagyva csak a sor száma változik Az #error direktíva célja: hibaüzenet generálása és a fordítás leállítása alakja: #error <hibaüzenet> újsor A #pragma direktíva célja: gép/os/fordító specikus utasítások a fordítónak alakja: #pragma <el feldolgozó-szimbólumok> újsor az el feldolgozó a számára ismeretlen #pragma direktívákat gyelmen kívül hagyja
Direktívák #ifdef, #ifndef, #line, #error,... line.c #include<stdio.h> #define PI 3.14 int main(void) { printf("ez a(z) %s fájl %d. sora.\n", FILE, LINE ); #line 100 "abrakadabra.c" printf("ez a(z) %s fájl %d. sora.\n", FILE, LINE ); #ifndef PI #error PI makró nem definiált! #endif printf("egységsugarú kör kerülete: %.3f\n", 2*1*PI); return 0; } Kimenet Ez a(z) line.c fájl 4. sora. Ez a(z) abrakadabra.c fájl 100. sora. Egységsugarú kör kerülete: 6.280 #define PI 3.14 törlése utáni kimenet abrakadabra.c: In function `main': abrakadabra.c:102:4: error: #error PI makró nem definiált! abrakadabra.c:104:55: error: `PI' undeclared (first use in this function)