El®feldolgozó Programozás I.
Hatwágner F. Miklós
Széchenyi István Egyetem, Gy®r 2013. október 16.
El®feldolgozó feladatai Emlékeztet®: forrásfájl kapcsoló-szerkeszt®
→
→
(el®feldolgozó
→
fordító)
→
futtatható állomány
El®feldolgozó 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)
Hatwágner F. Miklós
El®feldolgozó
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
Hatwágner F. Miklós
El®feldolgozó
Direktívák üres, include Üres (null) direktíva egyetlen # karaktert tartalmazó sor
include
→
elhagyja, hatástalan
direktíva
fájl tartalmának beszerkesztése, alakjai:
#include
ú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) Hatwágner F. Miklós
El®feldolgozó
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
Hatwágner F. Miklós
El®feldolgozó
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! Hatwágner F. Miklós
El®feldolgozó
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 Hatwágner F. Miklós
El®feldolgozó
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 Hatwágner F. Miklós
El®feldolgozó
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.
Hatwágner F. Miklós
El®feldolgozó
Direktívák undef, paraméteres define Makró deniálatlanná tétele
#undef azonosító újsor deniált azonosító -ra is kiadható
alakja: nem
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! →
Paraméteres
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
Hatwágner F. Miklós
El®feldolgozó
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; } Hatwágner F. Miklós
El®feldolgozó
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
Hatwágner F. Miklós
El®feldolgozó
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 Hatwágner F. Miklós
El®feldolgozó
Karakterek vizsgálata, átalakítása sok rendszerben függvényszer¶ makrókkal oldják meg
ctype.h
bekapcsolása szükséges
int, de az értéknek unsigned char-ral EOF-nak kell lennie érték int, karakterosztályozó rutinoknál logikai
Paraméter típusa
ábrázolhatónak, vagy Visszatérési
é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¶
Hatwágner F. Miklós
El®feldolgozó
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)) Hatwágner F. Miklós
El®feldolgozó
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 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); }
Hatwágner F. Miklós
El®feldolgozó
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. Hatwágner F. Miklós
El®feldolgozó
Feltételes fordítás alakja:
#if konstans-kifejezés1 <szekció1 > konstans-kifejezés2 <szekció2 >>
<#elif
/* ... */ <#elif
konstans-kifejezésN
<#else >
<szekcióN >>
#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, sizeof operátort, explicit
de pl. lebeg®pontos konstanst, típuskonverziót nem! az
#if
#endif
szerkezetek tetsz®leges mélységben
egymásba ágyazhatók Hatwágner F. Miklós
El®feldolgozó
Feltételes fordítás A
defined
operátor
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
fej.h #if !defined(_FEJ) #define _FEJ /* érdemi tartalom */ #endif Hatwágner F. Miklós
El®feldolgozó
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: A
#pragma
#error
újsor
direktíva
célja: gép/OS/fordító specikus utasítások a fordítónak
#pragma <el®feldolgozó-szimbólumok> újsor el®feldolgozó a számára ismeretlen #pragma direktívákat
alakja: az
gyelmen kívül hagyja Hatwágner F. Miklós
El®feldolgozó
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) Hatwágner F. Miklós
El®feldolgozó