Transcript
Page 1: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

11. Preprocesiranje i stndardni ulaz/izlaz

C-program se sastoji iz jedinaica za prevođenje (kompilacionih jedinica). Jedinica za prevođenje se sastoji iz izvorene datoteke i uključenih datoteka. Izvorna datoteka sadrži preprocesorske direktive i C-naredbe. U procesu prevođenja, kompilaciona jedinica se najpre podvrgava preprocesoru.Preprocesor priprema izvorni kod i prosleđuje ga prevodiocu. U toku rada, preprocesor prolazi kroz 4 faze, a rezultat njegovog rada je izmenjen izvorni program tako da su:

• izbačeni komentari • preprocesorske direktive su zamenjene rezultatom • njihovog izvršavanja

11.1. Preprocesiranje

Page 2: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

Preprocesor obavlja sledeće:

1. Iz izvorne datoteke učitavaju se program znak po znak po potrebi neki znaci se prevode u znakove iz skupa dozvoljenih izvornih.

2. Ako se iza znaka za novi red nalazi obrnuta kosa crta, preprocesor briše oba znaka.

3. Izvorna datoteka razlaže se na preprocesorske tokene i na sekvence blanko-simbola (razmaka). Svaki komentar zamenjuje se jednim razmakom.

4. Izvršavaju se preprocesorske direktiva i realizuju pozivi makroa.

Sve opisane radnje realizuju se i nad datotekama koje su umetnute pomoću direktive #include.

Page 3: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

U preprocesorske direktive spadaju direktive za:

umetanje sadržaja drugih izvornih datoteka

prepoznavanje delova koda koji se prevode samo pod određenim uslovima i

definisanje makroa – identifikatora koje preprocesor zamenjuje drugim tekstom.

Preprocesorska direktiva počinju znakom # i u redu se, osim nje, ne može naći ništa više. Završava se prvim znakom za novi red (posle njenog početka), Najkraća je prazna direktiva (koja je bez dejstva) i sastoji se samo iz zbaka #. Dozvoljeni su komentar i razmaci.

Ako direktiva ne može da se smesti u jedan red, na kraj prvog reda stavlja se \ (obrnuta kosa crta) i prenosi se u sledeći red.

Page 4: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

Primer:

#define ImeMakroa Pera, \

Ovo je Perin makro

Obrnuta kosa crta mora biti poslednji znak pre znaka za novi red.

Razmaci i tabulatori mogu se naći između znaka # i imena direktive. ( U prethodnom primeru ime direktive je define.)

Rezultat rada preprocesora može se videti ako se on pokrene kao poseban program, tj. ako se može pokrenuti prevodiloac tako da se izvrše samo preprocesorske direktive. Nadlje ćemo razmotriti

direktive uključenja datoteka

makroe

direktive uslovnog prevođenja

Page 5: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

11.1.1. Direktiva umetanja (#include)Dirrektivom umetanja preprocesor umesto nje umeće sadržaj određene datoteke. Postoje 2 načina da se navede datoteka koja se umeće:

#include <imedatoteke>

#include “imedatoteke”

U prvom slučaju uključuje se zaglavlje neke datoteke iz standardne biblioteke ili iz date implementacije. Na primer:

#include <math.h>

Pomoću drugog oblika mogu se umetnuti izvorne datoteke specifične za naš program. Na primer:

#include “mojaDat.h”

U direktivi #include mogu se koristiti makroi (o kojima će biti rečikasnije)

Page 6: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

Mesto na kojem se traže datoteke iz direktive #include, zavisi od konkretne implementacije jezika C. (Datoteke između uglastih zagrada obično traži u sistemskim folderima, a datoteke između navodnika, obično u tekućem folderu.) Ovde ime datoteke može sadržati i putanju do datoteke.

Direktive #include mogu biti ugnježdene, tj. datoteka umetnuta pomoću direktive #include, može i sama sdržati direktive #include. Preprocesor dozvoljava najviše 15 nivoa gnježđenja.

Prilikom gnjezdastog umetanja može se desiti da se neka datoteka 2 puta umetne (datoteka stdio.h je skoro svuda prisutna). Neka u datoteci “mojaOmiljena.h” postoji red: #include <stdio.h>. Ako u izvornu datoteku uključimo direktive:

#include <stdio.h>#include “mojaOmiljena.h”

tada bi stdio.h bila umetnuta 2 puta. Ovo se može sprečiti korišćenjem direktiva uslovnog prevođenja o kojim će još biti reči.

Page 7: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

11.1.2. Makro-direktive (makroi)Makro se definiiše pomoću direktive #define. Ovom direktivom se dodeljuje ime proizvoljnom tekstu. Preprocesor ime makroa, gde god se pojavi u izvornom kodu posle definisanja, zameniti tim tekstom. Najčešće se koristi za definisanje konstanti. Na primer:

#define MAX 100

Po konvenciji, ime makroa piše se velikim slovima da bi se razlikovalo od imena običnih promenljivih.

U makrou se ne može definisati preprocesorska direktiva koja će potom biti realizovana (čak iako je korektno definisana).

Makro može biti definisan

bez parametra ili

sa parametraima.

Page 8: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

11.1.2.1 Makroi bez parametaraImaju opšti oblik:

#define ime_makroa tekst_zamena

Ovede tekst_zamena može biti i prazan.

Primer: #define NASLOV “– Glavni sadrzaj –”

#define VELICIN_BAF (4*512)

Ako u programu postoje naredbe:

puts (NASLOV).

static char mojBafer[VELICINA_BAF];

onda bi , nakon rada preprocesora, bile izvršene zamene:

put (“– Glavni sadrzaj –”);

static char mojBafer[(4*512)];

Page 9: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

11.1.2.2. Makroi sa parametrimaMakroi sa parametrima liče na funkcije. Definišu se na 2 načina:

#define ime_makroa( [lista_parametra] ) tekst_zamena #define ime_makroa( [lista_parametra,] …) tekst_zamenaLista_parametra je lista identfikatora razdvojenih zapetama. Tri tačke označavaju jedna ili više dodatnih argumenata. Ne sme se pojavljivati razmak između imena makroa i leve male zagrade.

Prilikom zamene imena makroa tekstom, preprocesor umeće i odgovarajuće argumente koji zamenjuju parametre.

Ako imamo

#define DIST(x,y) ((x)>=(y) ? (x)-(y) : (y) – (x)) d= DIST (a, b+1.6);biće izvršena sledeća zamena:

d= ((a)>=(b+1.6) ? (a)-(b+1.6) : (b+1.6) –(a));

Page 10: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

Prema standardu C99 u definiciji makroa mogu se koristiti i tri tačke (...). Takav makro se poziva sa promenljivim brojem argumenata.

Unarni operator # (često de naziva i operator konverzije u znakovni niz), služi za konvertovanje argumenta makroa u znakovni niz. Na primer, ako imamo:

#define stampaj( par ) printf(#par “ = %f “, par)

stampaj(4*sin(1.0));

poziv makro iz poslednjeg reda svodi se na:

printf(“4*sin(1.0)” “= %f “, 4*sin(1.0));

Kako prevodilac spaja susedne linije znkovnih nizova, bilo bi:

printf(“4*sin(1.0) = %f “, 4*sin(1.0));

Makroi se mogu ubacivati unutar drugih makroa, može se koristiti poseban opertor ## za ubacivanje tokena (time se nećemo baviti!)

makro1.cpp

Page 11: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

11.1.3. Direktiva uslovnog prevođenjaPomoću ove direktive može se, pod određenim uslovima, zadržati ili zameniti deo izvornog koda. Na taj način program se može prilagoditi raznim sistemima bez posebnog menjanja izvorne datoteke.

Deo programa koji se uslovno prevodi počinje jednom od direktiva #if, #ifdef ili #ifndef, a završava se direktivom #endif. U njemu se može javiti proizvoljno mnogo direktiva #elif, a najviše jedna direktiva #else.

U ovim direktivama mogu se javiti uslovi koji su celobrojni preprocesorski izrazi. Oni su slični običnim celobrojnim C-izrazima (pojavljuju se razlike u korišćenju direktiva) i mogu sadržati operator defined (o kojem će biti reči).

Page 12: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

Direktiva #if ima sledeći opšti oblik:#if izraz1 [grupa1]

[#elif izraz2 [grupa2 ]]

…[#elif izraz(n)

[grupa(n) ]][#else [grupa(n+1)]]

#endif

Preprocesor računa vrednosti izraza sve dok ne naiđe na vrednost različite od nule (true) i tekst u odgovarajućoj grupi zadržava za dalu obradu. Ako nijedan nije true, a postoji #else, zadržava se tekst u grupi iza #else.

Grupe sadrže C-naredbe, a mogu sadržati i direktive.

Page 13: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

11.1.3.1. Operator definedU uslovnoj direktivi #if ili #elif može se naći unarni operator defined, koji ima jedan od sledećih oblika:

defined identifikator

defined (identifikator)

Preprocesorski izraz ima vrednost 1 ako je navedeni identifikator ime makroa, tj. ako je definisan pomoću direktive #define, a njegova definicija nije poništena pomoću direktive #undef. u suprotno, izraz sa operatorom defined je 0.

makro21.cpp

makro22.cpp

Page 14: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

11.1.3.2. Direktive #ifdef , #ifndef i #errorOve direktive služe, takođe, za proveru da li je neki makro definisan. Imaju sledeću sintaksu:

#ifdef identifikator

#ifndef identifikator.

One se jednostavno opisuju preko defined operatora:

#if defined identifikator

#if !defined identifikator.

Direktiva #error nalaže procesoru da ispiše poruku o grešci, bez obzira d ali greška formalno postoji. Ima sintaksu:

#error [tekst]

Ako postoji opcioni tekst, on će se pojaviti u poruci o grešci.

makro31.cpp makro32.cpp

Page 15: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

11.1.4. Unapred definisani makroiSvaki prevodilac koji podržava ISO C mora da definiše 7 sledećih makroa (njihova imena počinju i završavaju se dvema crtama za podvlačenje):

_ _ DATE _ _ tekst makroa je literal znakovnog niza koji sadrži datum prevođenja u formatu “Mes dd gggg”, npr. “Mar 23 2007”

_ _ FILE_ _ literal znakovnog tipa koji sadrži ime tekuće izvorne datoteke.

_ _ LINE _ _ celobrojna konstanta čija vrednost je broj reda u tekućoj izvornoj datoteci u kojem se poziva makro _ _ LINE_ _.

_ _ TIME_ _ literal zakovnog niza koji sadrži vreme prevođenja u formatu “hh:mm:ss”

_ _ STDC_ _ Celobrojna konstanta je 1 ako je podržan standar ISO C.

_ _STDC_HOSTED_ _ celobrojna koja ima vrednost 1 ako izvršavanje tekućeg programa zavisi od operativnog sistema, inače je 0.

_ _STDC_VERSION_ _ konstantta 199901 tipa long, ako je podržan C99

Page 16: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

11.2. Standardni ulaz/izlazStabdardne funkcije ulaza/izlaza smeštene su u standardne

biblioteke od kojih se najviše koristi <stdio,h>.

1. Za učitavanje jednog znaka koristi se finkcija:

int getchar(void)

2. Za štampanje jednog znaka koristi se funkcija:

int putchar(int)

3. Za štampanje koristi se funkcija:

int printf(char *format [, arg1, arg2, ...])

koja prevodi interne vrednosti (zapisane u računaru) u znakovne.

Može se opisati i ovako:

int printf(<format-string> [,arg1, arg2, …])

Page 17: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

Funkcija printf konvertuje, formatira i štampa svoje argumente na standardni izlaz pod kontrolom format-stringa i vraća broj odštampanih znakova. Format-string sadrži 2 tipa znakova:

znaci koji se kopiraju na izlaz ispecifikaciju konverzije, koja vrši konverziju i štampa

argumenteSvaka specifikacija konverzije počinje znakom % i završava se znakom konverzije. Između % i znaka konverzije može postojati:

znak – određuje levo poravnanje argumenatabroj – određuje minimalnu širinu polja (ako treba, proširuje

se!)tačka (.) – razdvaja širinu polja od tačnostitačnost – određuje broj cifara iza dec. tačke ili maksimalan

broj c ifara niske.h, l ili L – određujue short i long brojeve

Page 18: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

Znaci konverzije mogu biti:d,i int decimalni, celobrojnin int *x pokazivačkio int neoznačen oktalni celobrojnix, X int neoznačen heksadekadni (x~a,b,..., X~A,B, ...)u int neoznačeni celobrojnic char znakovni celobrojnis string niska-tipf float,

double razlomljeni ( [zn]m.dd…d)e, E float

double razlomljeni ([zn]m.dd…dExx)g, G float

double razlomljeni kraći zapis od %f i %e p void *x (void * ) x% ništa štampa %

Page 19: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

4. Funkcija

int sprintf(char *string, char *format [, arg1, arg2, ...])

ima isti efekat kao i finkcija printf, ali štampanje vrši u string umesto na standardni izlaz.

5. Funkcija

int scanf(char *format [,arg1, arg2, ...])

ili

int scanf(<format-string> [, arg1, arg2, …])

vrši konveryiju u suprotnom smeru u odnosu na printf. Argumenti su pokazivači i pokazuju gde se memoriše konvertovani podaci. Vraća se broj uspešno dodeljenih ulaznih podataka.

Page 20: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

Konverzioni string, u ovom slučaju, sadrži:

beline – koje se zanemaruju

obične znake (izuzev %) koji se moraju podudarati sa odgovarajućim znakom na ulazu

specifikaciju konverzije koja se satoji od %, opcionog znaka *za ukidanje dodeljivanja, opcionog broja – širine polja, opcionog h, l ili L i znaka konverzije.

6. Funkcija

int sscanf(char *string, char *format [, arg1, arg2, ...])

ili

int sscanf(<string>, <format-string> [, arg1, arg2, ...])

se primenjuje isto kao i scanf, jedino što vrši učitavanje iz navedenog stringa umesto sa standardnog ulaza.

Page 21: 1 1. Preprocesiranje  i stndardni ulaz/izlaz

Konvezioni znaci:

c pokazivač na char

d int

f float, double

e, E float. double

g, G float, double

i int

n int

o int oktalni

s string

u neoznačen ceo dekadni, x neoznačen ceo hesadekadni

[…] char x[]

% bez dejstva


Recommended