Kako podesiti pametne telefone i računare. Informativni portal
  • Dom
  • Savjet
  • Petlja za pretprocesor jezika sa. #Ifdef #ifndef direktive

Petlja za pretprocesor jezika sa. #Ifdef #ifndef direktive

C direktive predprocesora

C pretprocesor je program koji obrađuje ulaz u drugi program. C predprocesor skenira program do kompajlera, zamjenjuje skraćenice u tekstu programa odgovarajućim direktivama, pronalazi i povezuje potrebne datoteke, može uticati na uslove kompilacije. Direktive preprocesora zapravo nisu dio C jezika. Predprocesor uključuje sljedeće direktive:

Definicija

Imenovanje

Makro definicija

Nedefinisanje makroa

Uključujući naslovni objekt

Kompilacija ako je izraz istinit

Kompilacija ako je makro definiran

Kompilacija ako makro nije definiran

Kompilacija ako izraz u if je lažan

Drugačije / ako složena direktiva

Završetak kompilacijske grupe prema uvjetu

Zamijenite novim imenom reda ili originalnim imenom datoteke

Generisanje prevodnih grešaka

Akcija je definirana implementacijom

Null direktiva

Direktiva # definisati

Direktiva # definisati uvodi makroe ili makroe. Opšti oblik direktive je sljedeći:

# definisatiMACRO_NAME karakter_sekvenca

Niz znakova naziva se i zamjenski niz. Kada pretprocesor pronađe macro_name (samo makro) u izvornoj datoteci, on ga zamjenjuje s character_sequence.

Možete nadjačati definiciju makronaredbe s # undef direktivom:

# undefmacro_name

Ova linija uklanja sve prethodno unesene zamjenske nizove. Definicija makroa je izgubljena i macro_name postaje nedefinirano.

Na primjer, možete definirati MAX kao vrijednost od 100:

Ova vrijednost će se svaki put zamijeniti umjesto MAX makroa u izvornom fajlu. Također možete koristiti makro umjesto konstante niza:

#defineNAME “TurboC ++”

Ako niz znakova u direktivi ne stane u jedan red, onda možete staviti \ na kraj reda i nastaviti niz u drugom redu. Među programerima je dogovor da su imena makroa velika slova, jer ih je lako pronaći u programu. Također je bolje postaviti sve direktive # define na početak programa.

Direktiva # definisati ima još jedan važna karakteristika: makro može imati argumente. Svaki put kada dođe do zamjene, argumenti se zamjenjuju onima koji se pojavljuju u programu.

Primjer : #define MIN (a, b) ((9a)<(b)) ? (a) : (b)

printf („Minimum x i y“% d, MIN (x, y));

printf („Minimum a i b“% d, MIN (n, m));

Kada se program kompajlira, x i y ili m i n će biti zamijenjeni u izrazu definiranom sa MIN (a, b), respektivno. Argumenti a i b su zatvoreni u zagradama, jer se za njih može zamijeniti neki izraz, a ne samo identifikator.

Na primjer, printf (“Minimum“% d, MIN (x * x, x));

Direktiva # greška

Izgleda kao: # greškaerror_message

Ova komanda zaustavlja kompajliranje programa i prikazuje poruku o grešci.

Direktive o uslovnoj kompilaciji

Ove direktive uključuju: # ako, # ostalo, # elif, # endif.

Ove direktive vrše selektivnu kompilaciju programa. Ako je izraz nakon #if tačan, tada će se kompajlirati kodovi zatvoreni između # if i #endif. U suprotnom, oni će biti preskočeni tokom kompilacije. Izraz koji slijedi #if se provjerava u vrijeme kompajliranja, tako da može sadržavati samo konstante i makroe koji su prethodno definirani. Ovdje se ne mogu koristiti varijable.

Direktiva # ostalo koristi se na isti način kao Else u C.

primjer: Korištenje uvjetne kompilacije.

# uključuje

# definirajte MAX 100

printf (“MAX jednak% d \ n”, MAX);

Direktiva # elif koristi se za organiziranje ugniježđene uvjetne kompilacije. Oblik njegove upotrebe je sljedeći:

#if<выражение>

redosled izjava

#elif<выражение 1>

redosled izjava

#elif<выражение 2>

redosled izjava

…………………………………..

Druga metoda za uvjetnu kompilaciju je korištenje direktiva # ifdef i # ifndef. Glavni oblik korištenja ovih direktiva je sljedeći:

# ifdefMACRO_NAME

# endif

i shodno tome

# ifndefMACRO_NAME

redosled izjava

# endif

Ako je makro definiran, onda korištenje # ifdef kompajlira odgovarajući niz do #endif naredbi. Ako makro nije definiran ili ga je poništila #undef direktiva, kompajler ignorira odgovarajući niz naredbi. Direktiva # ifndef radi na suprotan način.

#include

Direktiva #include umeće kod iz specificirane datoteke u trenutni fajl, odnosno jednostavno povezivanjem drugog fajla možemo koristiti njegove funkcije, klase, varijable. Datoteke zaglavlja se obično nalaze ili u trenutnom direktoriju ili u standardnom sistemskom direktoriju.

Datoteke zaglavlja su uključene u vrijeme kompajliranja ili kao datoteka koja je dio vašeg projekta. Ova funkcija ovisi o specifičnoj implementaciji vašeg kompajlera, tako da dobijete više detaljne informacije, udubite se u postavke vašeg kompajlera.

Ako uključena datoteka nije pronađena, proces kompilacije neće uspjeti.

#Defini direktivu

Direktiva #define ima dva oblika:

  • definicija konstanti;
  • definicija makroa.
Definiranje konstanti
#define vrijednost nameTokena

Kada koristite ime konstante - nameToken, ono će biti zamijenjeno vrijednosnom vrijednošću, odnosno, grubo rečeno - to je ista varijabla čija se vrijednost ne može mijenjati. Pogledajmo primjer korištenja konstante:

#include #define TEKST "Mars" // definiraj konstantu int main () (std :: cout<< TEXT; return 0; }

Kao što vidite, da bismo pristupili vrijednosti konstante, jednostavno koristimo njeno ime.

Definiranje parametriziranih makroa

#define nameMacros (arg1, arg2, ...) izraz

Na primjer, hajde da definiramo makro koji će vratiti najviše dvije vrijednosti.

#define MAX (num1, num2) ((num1)> (num2)? (num1): (num2))

Pažnja, da biste definisali višelinijski makro, u svakom redu, na kraju, mora se staviti simbol koji obaveštava pretprocesor da makro još nije završen.

#Undef direktiva

Direktiva #undef nadjačava konstantni ili predprocesorski makro koji je prethodno definiran korištenjem direktive #define.

#undef nameToken

Pogledajmo primjer korištenja #undef direktive:

#define E 2.71828 // ranije definirani makro int sumE = E + E; // poziv na makro #undef E // sada E nije makro

Tipično, direktiva #undef se koristi za poništavanje prethodno definirane konstante ili makroa u malom dijelu programa. To se radi tako da za cijeli program ostane makro ili konstanta, a za određeno područje isti makro ili konstanta može biti redefinisana. Bilo bi nesigurno poništiti konstantu kroz program, ali u kratkom opsegu, relativno je sigurno. Direktiva #undef je jedini način da se kreira ovaj opseg, budući da se opseg makronaredbi ili konstanti kreće od #define do #undef.

#If direktiva

#if value // kod koji će se izvršiti ako je vrijednost istinita #elsif value1 // ovaj kod će se izvršiti ako je vrijednost1 true #else // kod koji će se izvršiti u suprotnom #endif

Direktiva #if provjerava da li je vrijednost istinita i, ako jeste, izvršava se kod prije zatvaranja #endif direktive. Inače, kod unutar #if neće prevesti, kompajler će ga ukloniti, ali to ne utiče na izvorni kod u izvornom kodu.

Imajte na umu da #if može sadržavati ugniježđene direktive #elsif i #else. Ispod je primjer koda za komentiranje blokova koda koristeći sljedeću konstrukciju:

#if 0 // kod za komentarisanje #endif

Ako imate blokove koda u svom programu koji sadrže komentare u više redaka i trebate umotati cijeli blok koda u komentar, ništa neće raditi ako koristite / * višeredni komentar * /. Druga stvar je konstrukcija #if #endif direktiva.

#Ifdef direktiva

#ifdef nameToken // kod koji će se izvršiti ako je nameToken definiran #else // kod koji će se izvršiti ako nameToken nije definiran #endif

Direktiva #ifdef provjerava da li je makro ili simbolička konstanta prethodno definirana kao #define. Ako - da, kompajler uključuje u program kod koji se nalazi između direktiva #ifdef i #else, ako nameToken nije prethodno definiran, tada se izvršava kod između #else i #endif, ili, ako ne postoji #else direktive, kompajler odmah ide na # endif. Na primjer, __cpp makro je definiran u C ++, ali ne u C. Možete koristiti ovu činjenicu da pomiješate C i C ++ kod koristeći #ifdef direktivu:

#ifdef __cpp // C ++ kod #else // C kod #endif

#Ifndef direktiva

#ifndef nameToken // kod koji će se izvršiti ako nameToken nije definiran #else // kod koji će se izvršiti ako je nameToken definiran #endif

Direktiva #ifndef provjerava da li je makro ili simbolička konstanta prethodno definirana kao #define. Ako je odgovor da, kompajler uključuje u program kod koji se nalazi između #else i #endif direktiva, ako nameToken nije prethodno definiran, tada se izvršava kod između #ifndef i #else, ili, ako ne postoji #else direktiva , kompajler odmah skače na # endif. Direktiva #ifndef se može koristiti za uključivanje datoteka zaglavlja. ako nisu povezani, za to koristite simboličku konstantu kao indikator funkcionalnosti povezane s projektom.

Na primjer, datoteka zaglavlja sadrži sučelje klase koje mora biti povezano s projektom ako ova klasa nije prethodno bila povezana.

#ifndef PRODUCT_H #define PRODUCT_H klasa Proizvod (// kod klase ...); #endif PRODUCT_H

U ovom slučaju se koristi prazna simbolička konstanta PRODUCT_H, koja se može definirati samo u programu zajedno s klasom Product. Stoga, ako utvrdimo da je konstanta PRODUCT_H već definirana, onda je i klasa, a onda ćemo isključiti redefiniranje klase, što može dovesti do greške u preglasavanju.

#Error direktiva

#error "Ovaj kod ne bi trebao kompajlirati"

Direktiva #error vam omogućava da prikažete poruku na listi grešaka kompilacije ako dođe do odgovarajuće greške. Ova direktiva je najkorisnija u kombinaciji sa #if, #elsif, #else direktivama za provjeru kompilacije ako neki uvjet nije istinit. Na primjer:

#ifndef __unix__ // __unix__ je obično podržan na Unix sistemima #error "Podržano samo na Unixu" #endif

__FILE__ preprocesorski makro

Makro predprocesora __FILE__ proširuje se na punu putanju do trenutnog fajla (izvora). __FILE__ je koristan za kreiranje log fajla, generisanje poruka o grešci namenjenih programerima, prilikom otklanjanja grešaka koda.

Int greška (const char * adrFile, const std :: string & erMessage) (cerr<< "[" << adrFile << "]" << arMessage << endl; } #define LOG(erMessage) error(__FILE__, arMessage) // макрос LOG может быть использован для получения сообщений об ошибках, которые выводятся на стандартный поток ошибок

Makro __FILE__ se često koristi zajedno sa makroom __LINE__, koji daje trenutni broj reda.

__LINE__ makro predprocesora

Makro __LINE__ se proširuje na trenutni broj reda u izvornom fajlu kao cjelobrojna vrijednost. __LINE__ je koristan za generiranje datoteke dnevnika ili generiranje poruka o grešci broja reda za programere prilikom otklanjanja grešaka koda.

Int greška (int nLine, const std :: string & erMessage) (cerr<< "[" << nLine << "]" << erMessage << endl; } #define LOG(erMessage) error(__LINE__, erMessage) // макрос LOG может быть использован для получения сообщений об ошибках, с указанием номеров строк, которые выводятся на стандартный поток ошибок

Makro __LINE__ se često koristi u sprezi sa makroom __FILE__, koji pokazuje adresu trenutnog izvorni fajl.

__DATE__ preprocesorski makro

Makro __DATE__ proširuje se na trenutni datum (vrijeme kompajliranja) kao [mmm dd gggg] (na primjer, "7. decembar 2012."), kao niz. __DATE__ se može koristiti za pružanje informacija o vremenu prevođenja.

Cout<< __DATE__ << endl;

Također možete koristiti makro __TIME__ da dobijete trenutno vrijeme kompajliranja.

__TIME__ preprocesorski makro

Makro __TIME__ proširuje se u trenutno vrijeme (vrijeme kompajliranja) u hh: mm: cc formatu u 24-satnom formatu (na primjer, "22:29:12"). Makro __TIME__ može se koristiti za pružanje informacija o vremenu u određenom trenutku u kompilaciji.

Cout<< __TIME__ << endl;

__TIMESTAMP__ preprocesorski makro

Makro __TIMESTAMP__ se proširuje u trenutno vrijeme (vrijeme kompajliranja) u formatu Ddd Mmm Datum hh :: mm :: ss gggg, vrijeme u 24-satnom formatu:

  • Ddd je skraćeni dan u sedmici,
  • mmm ovo je skraćeno kao mjesec,
  • Datum - tekući dan u mjesecu (1-31),
  • yyyy su četiri cifre godine.

Na primjer, "Petak 7. decembar 00:42:53 2012.". __TIMESTAMP__ makro se može koristiti za dobijanje informacija o datumu i vremenu kompilacije.

Cout<< __TIMESTAMP__ << endl;

Također možete koristiti makro __TIME__ da dobijete trenutno vrijeme kompajliranja i makro __DATE__ da dobijete datum.

#Pragma direktiva

#pragma specifična ekstenzija za kompajler

Direktiva #pragma se koristi za pristup specifičnim ekstenzijama kompajlera. Upotreba #pragma direktive sa tokenom jednom traži od prevodioca da uključi datoteku zaglavlja samo jednom, bez obzira koliko puta je uvezena:

#pragma jednom // datoteka zaglavlja

U ovom primjeru, direktiva #pragma jednom ne dozvoljava da se datoteka više puta uključi u projekat, odnosno sprječava nadjačavanje.

Direktiva #pragma se također može koristiti u druge svrhe, na primjer #pragma se obično koristi za onemogućavanje upozorenja. Na primjer, u MVS:

#pragma upozorenje (onemogućeno: 4018)

Direktiva #pragma u ovom primjeru se koristi za onemogućavanje upozorenja 4018. Za više korištenja direktive #pragma, pogledajte dokumentaciju vašeg kompajlera.

Makro operater #

#

Operator # tekstualni token u nizu pod navodnicima. Pogledajmo primjer:

#include korištenje imenskog prostora std; #define poruka(e) cout<< "Сообщение: " #s << endl; int main() { message("GunGame"); return 0; }

Spojite nizove i proširite makro poruke na cout<< "Сообщение: GunGamen"; . Обратите внимание на то, что операция # должна использоваться совместно с аргументами, так как # ссылается на аргумент.

Makro operater ##

## operator uzima dva odvojena tokena i lijepi ih ​​zajedno da formiraju jedan makro. Rezultat može biti ime varijable, ime klase ili bilo koji drugi identifikator. Na primjer:

#define type ch ## ar type a; // varijabla a je tip podataka char, pošto su ch i ar zalijepljeni za char

Razmotrimo još jedan primjer korištenja ## operatora, u kojem kombiniramo dva tokena:

#define TOKENCONCAT (x, y) x ## y

Kada program pozove ovaj makro, dva tokena se spajaju u jedan. Operacija ## mora imati dva operanda.

PS.: Svaki ozbiljan program mora imati svoju bazu podataka, obično se za upravljanje bazom koriste sljedeći DBMS: MySQL, MsSQL, PostgreeSQL, Oracle itd. Prilikom instaliranja sql servera, forum na cyberforum.ru će biti nezamjenjiv pomoćnik za ti. Postavljajte svoja pitanja na ovom forumu, sigurno će vam se pomoći u rješavanju vašeg problema.

Preprocesorske direktive

Svaki put kada se kompajler pokrene, prvi se pokreće predprocesor, koji izvršava direktive počevši sa znakom #. Ove naredbe kreiraju privremeni izvorni kod sa kojim kompajler već radi.

Direktiva #Include

Linija
#include "filename"

Zamjenjuje ovaj red punim sadržajem naziva datoteke. fajl. Ako putanja nije navedena, tada se datoteka prvo traži u direktoriju izvorne datoteke, a zatim u direktoriju navedenom u opcijama kompajlera (obično direktorij Include).

Linija #include<имя файла>

Traži datoteku samo u direktoriju navedenom u opcijama kompajlera.

#Defini direktivu

#define niz znakova id

Zamjenjuje sva naknadna pojavljivanja identifikatora nizom znakova. primjer:

#defini A_BROJ 100

int n = A_BROJ;

n će biti dodijeljena vrijednost 100

#define se također može koristiti za definiranje makronaredbi, na primjer:

#define SWAP (a, b) temp = (a); (a) = (b); (b) = temp

Više detalja o #define (a posebno o makroima) bit će poseban članak.

#Undef direktiva

#undef identifikator

Nadjačava definiciju identifikatora predprocesora.

#If #else #endif direktive

#if izraz

Provjerava da li je izraz tačan, i ako je istinit, zatim izvršava sve sljedeće linije do #endif direktive.

Vrsta konstrukcije:

#if izraz

#endif Provjerava izraz, ako je istinit onda se izvršavaju linije između #if i #else, a ako je netačan onda između #else i #endif.

#Ifdef #ifndef direktive

#ifdef identifikator

Provjerava da li je identifikator definiran u pretprocesoru u ovog trenutka(po #define direktivi) i ako je definirano, onda izvršava sve naredne linije do #endif direktive.

#ifndef identifikator

Naprotiv, izvršava sve naredne linije do #endif direktive ako identifikator trenutno nije definiran u pretprocesoru.

#Error direktiva

#greška- poruka o grešci. Zaustavlja kompajler i prikazuje poruku o grešci. Na primjer:

#ifndef smth_important

#error nešto važno nije definirano

Kompajler će vratiti nešto poput:

Fatal F1003 file.cpp 2: Direktiva o grešci: nešto važno nije definirano

*** 1 greška u kompajliranju ***

#Line direktiva

Direktiva
#line konstanta "ime datoteke" Uzrokuje kompajler da pretpostavi da je konstanta broj sljedećeg reda izvorne datoteke, a trenutna ulazna datoteka je imenovana identifikatorom. Ako je identifikator odsutan, tada se zapamćeno ime datoteke ne mijenja.

#Pragma direktiva

#pragma je predprocesorska direktiva koja implementira mogućnosti kompajlera. Ove karakteristike mogu biti povezane sa tipom kompajlera; različiti tipovi kompajlera mogu podržavati različite direktive. Opšti pogled na direktivu:

#pragma naredba kompajlera

Na primjer:

#pragma poruka ("poruka")- samo ispisuje poruku o kompilaciji.

Opsegovi

Funkcije i vanjske varijable koje čine C program, nema potrebe svaki put sve zajedno kompajlirati. Originalni tekst se može pohraniti u više datoteka. Prethodno kompajlirani programi mogu se učitati iz biblioteka. S tim u vezi nameću se sljedeća pitanja:

Kako da napišem deklaracije tako da varijable koje se koriste budu pravilno deklarirane tokom kompilacije?

Kojim redoslijedom treba postaviti deklaracije da bi svi dijelovi programa bili povezani na pravi način prilikom učitavanja?

Kako da organiziram svoje oglase tako da imaju samo jednu kopiju?

Kako da inicijaliziram vanjske varijable?

Počnimo s razbijanjem kalkulatora u nekoliko datoteka. Naravno, ovaj program je premali da bi ga vrijedilo podijeliti na datoteke, ali podjela našeg programa će nam omogućiti da demonstriramo probleme koji se javljaju u velikim programima.

Obim Ime se smatra dijelom programa u kojem se ime može koristiti. Za automatske varijable deklarirane na početku funkcije, opseg je funkcija u kojoj su deklarirane. Lokalne varijable različitih funkcija, koje, međutim, imaju isto ime, nisu ni na koji način povezane jedna s drugom. Isto vrijedi i za parametre funkcije, koji su zapravo lokalne varijable.

Opseg eksterne varijable ili funkcije proteže se od tačke u programu u kojoj je deklarisana do kraja datoteke koju treba prevesti. Na primjer, ako main, sp, val, gurnuti i pop su definisani u istoj datoteci prikazanim redosledom, tj.

Main () (...) int sp = 0; double val; praznina guranje (dvostruko f) (...) duplo iskakanje (praznina) (...)

zatim na varijable sp i val može se obratiti iz gurnuti i pop jednostavno po njihovim imenima; za ovo nisu potrebne dodatne najave. Imajte na umu da u main ova imena nisu vidljiva tako dobro kao oni sami gurnuti i pop.

Međutim, ako eksternu varijablu treba referencirati prije nego što je definirana, ili ako je definirana u drugoj datoteci, tada bi njena deklaracija trebala biti označena riječju extern.

Važno je razlikovati najava vanjska varijabla od svoje definicije... Deklaracija deklarira svojstva varijable (prije svega njen tip), a definicija, osim toga, vodi do dodjele memorije za nju. Ako su linije

Int sp;dvostruki val;

se nalaze izvan svih funkcija, onda oni definisati eksterne varijable sp i val, tj. dodijeliti memoriju za njih, a također služe kao deklaracije za ostatak izvorne datoteke. A evo i redova

Extern int sp;extern double val;

najaviti za ostatak fajla koji sp- varijabla tipa int, a val- niz tipa duplo(čija je veličina određena na drugom mjestu); u ovom slučaju se ne kreiraju ni varijabla ni niz, a memorija im se ne dodjeljuje.

Za čitav skup datoteka koje čine originalni program, za svaku eksternu varijablu mora postojati jedna i jedina definicija; druge datoteke moraju imati deklaraciju u sebi da bi pristupile vanjskoj varijabli extern... (Međutim, najava extern može se postaviti u datoteku koja sadrži definiciju.) Definicije niza moraju specificirati njihove veličine, koje u deklaracijama extern nije potrebno. Eksterna varijabla se može inicijalizirati samo u definiciji. Iako teško da se isplati organizirati naš program na ovaj način, mi ćemo definirati push i pop u jednom fajlu, a val i sp u drugom, gdje ih inicijaliziramo. Međutim, da biste uspostavili veze, potrebne su vam sljedeće definicije i deklaracije:

U fajlu 1: extern int sp, extern double val; praznina guranje (dvostruko f) (...) duplo iskakanje (praznina) (...) U fajlu 2: int sp = 0, dupli val;

Od reklama extern su na početku file1 a izvan definicija funkcija, primjenjuju se na sve funkcije, s jednim skupom deklaracija dovoljnim za sve file1... Ista organizacija extern-deklaracije su potrebne iu slučaju kada se program sastoji od jedne datoteke, ali se definicije sp i val nalaze nakon njihove upotrebe.

Nacionalni otvoreni univerzitet "INTUIT": www.intuit.ru Nina Kalinina, Nina Kostyukova Predavanje 11. Preprocesor jezika C

Opće informacije

Integrisano okruženje za pripremu programa u C-u ili kompajler jezika kao obaveznu komponentu uključuje pretprocesor. Svrha pretprocesora je da obradi izvorni kod programa prije nego što se prevede. Predobrada uključuje nekoliko faza koje se izvode uzastopno. Konkretna implementacija može kombinovati nekoliko faza, ali rezultat bi trebao biti kao da se izvršavaju sljedećim redoslijedom:

1. Sve oznake koje zavise od sistema se pretvaraju u standardne kodove.

2. Svaki par karaktera"\ "i" kraj reda "zajedno sa razmacima između njih se uklanjaju i tako se sljedeći red izvornog teksta dodaje redu u kojem se nalazi ovaj par znakova.

3. Preprocesorske direktive i tokeni se prepoznaju u tekstu, a svaki komentar se zamjenjuje jednim znakom za razmak.

4. Izvrše se direktive pretprocesora i izvode se zamjene makroa.

5. Escape sekvence u znakovnim konstantama i znakovnim nizovima zamjenjuju se njihovim ekvivalentima.

6. Susedni nizovi znakova su spojeni, odnosno spojeni u jedan niz.

7. Svaki predprocesorski token se konvertuje u C tekst.

Hajde da objasnimo šta se podrazumeva pod predprocesorskim tokenima ili predprocesorskim tokenima. To uključuje konstante znakova, uključuje nazive datoteka, identifikatore, op oznake, brojeve pretprocesora, znakove interpunkcije, konstante niza i sve znakove osim razmaka.

Faza obrade predprocesorskih direktiva. Kada se izvrši, moguće su sljedeće radnje: zamjena identifikatora sa prethodno pripremljenim nizovima znakova; uključivanje tekstova iz navedenih datoteka u program; isključivanje iz programa pojedinih delova njegovog teksta, uslovno sastavljanje;

makro supstitucija, odnosno zamjena oznake parametriziranim tekstom koji generiše pretprocesor uzimajući u obzir specifične argumente.

Simboličke konstante: #define

Ako se simbol # koristi kao prvi znak u programskoj liniji, onda je ovaj redak komandna linija pretprocesor (makroprocesor). Komandna linija Pretprocesor završava znakom za novi red. Ako stavite obrnutu kosu crtu "\" neposredno prije kraja reda, onda komandna linija nastavit će se na sljedeći red programa.

Direktiva #define, kao i sve direktive preprocesora, počinje sa # na krajnjoj lijevoj poziciji. Može se pojaviti bilo gdje u izvornom fajlu, a data definicija je važeća od mjesta gdje se pojavljuje do kraja datoteke. Aktivno koristimo ovu direktivu za definiranje simboličke konstante u našim primjerima programa, međutim, ima širu primjenu, što ćemo pokazati sljedeće.

Zamjena identifikatora

#define id string

Zamjenjuje svako pojavljivanje ABC identifikatora u tekstu programa sa 100:

#undef identifikator

Preprocesor C jezika

Preokreće prethodnu definiciju za ABC identifikator.

/ * Jednostavni primjeri direktive preprocesora * / #define TWO 2 / * mogu se koristiti komentari * / #define MSG "Tekst 1. \

Nastavak teksta 1"

/ * obrnuta kosa crta nastavlja definiciju na sljedeći red * / #define ČETIRI DVA * DVA

#define PX printf ("X je% d. \ n", x) #define FMT "X je% d. \ n"

int x = DVA; PX;

x = ČETIRI; printf (FMT, x); printf ("% s \ n", MSG); printf ("DVA: MSG \ n"); povratak TWO;

V Kao rezultat izvođenja našeg primjera, imat ćemo:

X je jednako 2 X je jednako 4

Tekst 1. Nastavak teksta 1 DVA: MSG

Hajde da pogledamo šta se desilo. Operater

pretvara u

Zatim operater

pretvara u

printf ("X je% d. \ n", x);

pošto je izvršena potpuna zamjena. Sada vidimo da makro definicija može predstavljati bilo koji niz, čak i cijeli izraz u jeziku C. Imajte na umu da je ovo konstantni niz. PX će ispisati samo varijablu pod nazivom x.

V sljedeći red radi sljedeće: x = ČETIRI;

okreta

www.intuit.ru/studies/professional_skill_improvements/1747/courses/43/print_lecture/663

Preprocesor C jezika

pretvara u

i tu se završava. Stvarno množenje se ne dešava tokom pretprocesora ili kompilacije, već uvek, bez izuzetka, kada je program pokrenut. Pretprocesor ne izvodi proračune... To samo čini predložene zamjene vrlo precizno. Imajte na umu da makro definicija može uključivati ​​druge definicije. Neki prevodioci ne podržavaju ovo svojstvo gniježđenja. U sljedećem redu

pretvara u

printf ("X je% d. \ n", x)

kada je FMT zamijenjen odgovarajućim nizom. Ovaj pristup može biti vrlo zgodan ako postoji dugačak niz koji koristimo više puta. Sljedeći red programa zamjenjuje MSG odgovarajućim nizom. Navodnici čine zamjenski niz konstantom niza znakova. Kako program primi svoj sadržaj, ovaj niz će biti pohranjen u nizu sa nultom završetkom. dakle,

#define HAL "X" definira karakternu konstantu i

#define HAR "X" definira niz znakova X \ 0

Obično pretprocesor, kada naiđe na jedan od makroa u programu, vrlo precizno ih zamjenjuje ekvivalentnim zamjenskim nizom. Ako ova linija također sadrži makroe, oni se također poništavaju. Jedini izuzetak od ove zamjene je makro koji se nalazi unutar dvostrukih navodnika. Dakle

printf ("DVIJE: MSG");

ispisuje doslovno DVA: MSG umjesto ispisa sljedećeg teksta:

2: „Tekst 1.

Nastavak teksta 1"

Ako trebamo ispisati ovaj tekst, možemo koristiti operator

printf ("% d:% s \ n", DVA, MSG);

jer su makroi ovdje izvan navodnika.

Kada koristiti simboličke konstante? Vjerovatno bismo ih trebali primijeniti za većinu brojeva. Ako je broj konstanta koja se koristi u proračunima, onda simbolično imečini njegovo značenje jasnijim. Ako je broj veličina niza, onda simbolično ime olakšava modifikaciju vašeg programa kada radite sa velikim nizom. Ako je broj sistemski kod, recimo za znak EOF, onda simbolički prikaz čini program prenosivijim. Mijenja se samo definicija EOF-a. Mnemoničko značenje, lakoća promjene, prenosivost: sve to radi

simboličke konstante vrijedan pažnje!

Korištenje argumenata sa #define

Da biste izbjegli greške pri evaluaciji izraza, parametri macros potrebno je zaključiti

u zagradi.

#define id1 (id2,...) string

#defini trbušne mišiće (A) (((A)> 0)? (A): - (A))

www.intuit.ru/studies/professional_skill_improvements/1747/courses/43/print_lecture/663

Preprocesor C jezika

Svako pojavljivanje izraza abs (arg) u tekstu programa zamjenjuje se sa

((arg)> 0)? (arg): - (arg),

a parametar makro definicije A je zamijenjen sa arg.

#define nmem (P, N) \

(P) -> p_mem [N] .u_long

Znak \ nastavlja makro definiciju u drugom redu. Ova makro definicija smanjuje složenost izraza koji opisuje niz unija unutar strukture.

Makro definicija s argumentima je vrlo slična funkciji, jer su njeni argumenti zatvoreni u zagradama:

/ * makro definicija sa argumentima * / #define KVADRAT (x) x * x

#define PR (x) printf ("x jednako % d. \ n", x)

PR (KVADRAT (x + 2));

PR (100 / KVADRAT (2));

PR (KVADRAT (++ x)); return 0;

Gdje god se makro SQUARE (x) pojavi u našem programu, on se zamjenjuje sa x * x. Za razliku od naših prethodnih primjera, kada se koristi ovaj macros potpuno smo slobodni koristiti druge znakove osim x. U definiciji makroa, "x" je zamijenjen znakom koji se koristi u pozivu makroa programa. Stoga je makro definicija KVADRAT (2) zamijenjena sa 2 * 2. Dakle, x djeluje kao argument. ali, makro argument ne radi - baš kao argument funkcije. Evo rezultata pokretanja programa:

z je 16. z je 4.

KVADRAT (x) je 16. KVADRAT (x + 2) je 14.100 / KVADRAT (2) je 100. KVADRAT (++ x) je 30.

Prva dva reda su očigledna. Imajte na umu da čak i unutar dvostrukih navodnika u PR definiciji, varijabla je nadjačana odgovarajućim argumentom. Svi argumenti u ovoj definiciji su poništeni. Razmotrite treću liniju:

Postaje sljedeći red:

printf ("SQUARE (x) jednak% d. \ n", SQUARE (x));

www.intuit.ru/studies/professional_skill_improvements/1747/courses/43/print_lecture/663

Preprocesor C jezika

nakon prve faze makro ekspanzije. Drugi KVADRAT (x) se proširuje u x * x, dok prvi ostaje nepromijenjen jer se sada nalazi unutar navodnika u programskom izrazu i tako zaštićen od daljeg proširenja. Konačno, programska linija sadrži

printf ("SQUARE (x) jednak% d. \ n", x * x);

i otisci

KVADRAT (x) je jednako x * x.

Ako makro uključuje argument s dvostrukim navodnicima, tada će argument biti zamijenjen nizom iz poziva makroa. Ali nakon toga se više ne proširuje, čak i ako je niz druga makro definicija. U našem primjeru, varijabla x postala je makro definicija KVADRAT (x) i tako ostaje. Podsjetimo da je x = 4. Ovo sugerira da će KVADRAT (x + 2) biti 6 * 6 ili 36. Ali štampani rezultat kaže da je broj 14. Razlog za ovaj rezultat je taj što predprocesor ne vrši računanje. Samo zamjenjuje niz. Gdje god naša definicija ukazuje na x, pretprocesor će zamijeniti string x + 2.

Na ovaj način,

x * x postaje x + 2 * x + 2

Ako je x jednako 4, ispada

4+2*4+2=4+8+2=14

Poziv funkcije prosljeđuje vrijednost argumenta funkciji tokom vodeće vrijeme programe. Makro poziv prosljeđuje niz argumenata programu prije nego što se prevede.

Makro ili funkcija?

! Mnogi zadaci se mogu postići korištenjem makronaredbi s argumentima ili funkcijom. Koju treba primijeniti? Ne postoje stroga pravila o tome, ali postoje neka razmatranja.

Makro definicije treba koristiti kao trikove, a ne kao regularne funkcije. Mogu imati neželjene nuspojave. Neki kompajleri ograničavaju macros u jednom redu, i čini se da je bolje pridržavati se takvog ograničenja, čak i ako vaš kompajler to ne čini.

Izbor macros dovodi do povećanja količine memorije, a izbor funkcije - do povećanja vremena izvođenja programa. Makro definicija generiše linijski kod, tj. dobijamo operatera u programu. Ako se makro definicija primeni 20 puta, tada će 20 linija koda biti umetnuto u program. Ako upotrijebimo funkciju 20 puta, tada ćemo imati samo jednu kopiju izraza funkcije. Međutim, kontrola nad programom se mora prenijeti na lokaciju funkcije, a zatim vratiti u program koji poziva, što će potrajati više od rada sa linijskim kodovima. Zato razmislite šta odabrati!

Prednost makronaredbi je u tome što ne moramo da brinemo o tipovima varijabli kada ih koristimo. macros baviti se nizovima znakova, a ne stvarnim vrijednostima. Dakle, naša makro definicija SQUARE (x) može se jednako dobro koristiti sa varijablama kao što su int ili float.

Podsjetimo se!

1. U makro definiciji nema razmaka, ali se mogu pojaviti u redu za zamjenu. Predprocesor pretpostavlja da se makro definicija završava na prvom razmaku, tako da sve što dođe nakon prostora ostaje u redu za zamjenu.

2. Koristite zagrade za svaki argument i cijelu definiciju. Ovo je da bi se osiguralo da su elementi pravilno grupirani u izrazu.

3. Koristite velika slova za nazive makro funkcija. Ova konvencija se ne proteže tako široko kao konvencija kapitalizacije za makro konstante. Njihova upotreba će upozoriti na moguće nuspojave.

www.intuit.ru/studies/professional_skill_improvements/1747/courses/43/print_lecture/663

Preprocesor C jezika

macros.

Pretpostavimo da smo sami razvili nekoliko makrofunkcija. Ako pišemo novi program, ne bismo ih trebali nadjačati. Morate koristiti direktivu # include.

Datoteka uključuje: #include

Lista oznaka za fajlove zaglavlja za rad sa bibliotekama kompajlera odobrena je jezičkim standardom. Ispod su nazivi ovih datoteka, kao i kratke informacije o opisima i definicijama koje su uključene u njih. Većina opisa su prototipovi standardnih funkcija, ali su konstante uglavnom definirane, na primjer EOF, neophodne za rad sa bibliotečkim funkcijama.

assert.h - dijagnostika programa

ctype.h - konverzija znakova i provjera

errno.h - provjera greške

float.h - rad sa stvarnim podacima

limits.h - ograničenja za cijeli broj podataka

locale.h - nacionalna podrška okolišu

math.h - matematički proračuni

setjump.h - mogućnosti ne-lokalnih skokova

signal.h - rukovanje izuzetkom

stdarg.h - podrška za varijabilni broj parametara stddef.h - dodatne definicije

stdio.h - I/O objekti

stdlib.h - funkcije opće namjene (rad sa memorijom) string.h - rad sa nizovima znakova

time.h - definiranje datuma i vremena

U određenim implementacijama, broj i naziv datoteka zaglavlja mogu biti različiti. Na primjer, kompajleri za MS-DOS aktivno koriste datoteke zaglavlja mem.h, alloc.h, conio.h, dos.h i druge. Kompajleri Turbo C, Borland C++ koriste header fajl grafika.h.

Komandna linija#include se može pojaviti bilo gdje u programu, ali obično se sve inkluzije postavljaju na početak izvorne datoteke.

#include<имя_файла>

#include

Procesor zamjenjuje ovu liniju sa sadržajem math.h. Ugaone zagrade znače da će datoteka math.h biti preuzeta iz nekog standardnog direktorija (obično /usr/include). Trenutni direktorij se ne prati:

#include "filename"

Predprocesor zamjenjuje ovu liniju sa sadržajem ABC datoteke. Pošto je datoteka zatvorena pod navodnicima, pretraga se vrši u trenutnom direktoriju (koji sadrži glavni izvorni fajl). Ako ova datoteka ne postoji u trenutnom direktoriju, pretraga se izvodi u direktorijima navedenim imenom staze u opciji -l pretprocesora. Ako tamo nema datoteke, onda se skenira standardni direktorij.

www.intuit.ru/studies/professional_skill_improvements/1747/courses/43/print_lecture/663

Preprocesor C jezika

V operativni sistem UNIX ugaone zagrade govore predprocesoru da traži datoteku u jednom ili više standardnih sistemskih direktorija. Navodnici mu govore da prvo pogleda u vaš direktorij ili negdje drugdje ako ga navedete imenom datoteke, a zatim pogledate na standardnim mjestima.

V u određenim implementacijama, broj i nazivi datoteka zaglavlja mogu biti različiti:

#include "/user/1/my.h" izgleda u / user / 1 direktoriju

U tipičnom mikroprocesorskom sistemu, ova dva oblika su sinonimi, a pretprocesor pretražuje navedeni disk.

#include "stdio.h" pretražuje standardni disk

#include traži na standardnom disku

#include "a: stdio.h" pretražuje disk a

Po konvenciji, .h sufiks se koristi za datoteke zaglavlja, tj. datoteke sa informacijama koje se nalaze na početku programa. Datoteke zaglavlja obično se sastoje od izjava pretprocesora.

Neke datoteke su uključene u sistem, na primjer, stdio.h, ali možete kreirati svoje.

Mnogi programeri dizajniraju sopstvene standardne datoteke zaglavlja za upotrebu u svojim programima.

Uslovna kompilacija

Komandne linije pretprocesori se koriste za uslovno prevođenje različitih delova izvornog koda u zavisnosti od spoljnih uslova.

#ako konstantni_izraz

Tačno ako je konstantni izraz ABC + 3 različit od nule.

#ifdef identifikator

true ako je identifikator ABC prethodno definiran naredbom #define.

#ifndef identifikator

true ako ABC trenutno nije definiran.

Ako prethodne #if, # ifdef ili # ifndef provjere procijene na Tačno, redovi # else do # endif se zanemaruju tokom kompilacije.

Komanda #endif označava kraj uslovne kompilacije.

fprintf (stderr, "lokacija: x =% d \ n", x); #endif

Pomoćne direktive

Broj linije i naziv datoteke

#line int "ime datoteke"

Predprocesor mijenja broj tekućeg reda i ime kompajlirane datoteke. Naziv datoteke se može izostaviti.

Jedan od ciljeva korištenja uvjetne kompilacije je učiniti vaš program prenosivijim. Promjenom nekoliko definicija ključeva na početku datoteke, možemo postaviti različite vrijednosti i uključiti različite datoteke za različite sisteme.

#define N 3 / * definiraj konstantu * /

#red 55 "file.c"

Reakcija na greške

#error sekvenca tokena

Obrada direktive rezultira dijagnostičkom porukom u obliku definiranom nizom tokena. Korištenje ove direktive u kombinaciji s uvjetnim naredbama predprocesora.

U budućnosti možete provjeriti njegovu vrijednost i poslati poruku ako NAME ima drugačiju vrijednost:

#error NAME mora biti 15!

Poruka će izgledati ovako:

greška<имя_файла><номер_строки >;

greška direktiva: NAME mora biti 15!

Prazna direktiva

www.intuit.ru/studies/professional_skill_improvements/1747/courses/43/print_lecture/663

FILE__

Preprocesor C jezika

Korištenje ove direktive ne uzrokuje nikakvu radnju.

Ova direktiva definira radnje koje zavise od specifične implementacije kompajlera. Na primjer, neki prevodioci uključuju varijantu ove direktive kako bi obavijestili kompajler o prisutnosti naredbi asemblerskog jezika u tekstu programa. Mogućnosti naredbe #pragma mogu biti različite. Za njih ne postoji standard. Ako određeni predprocesor naiđe na pragmu koju ne poznaje, on je jednostavno ignoriše kao praznu direktivu. Neke implementacije uključuju pragmu.

#pragma paket (n), gdje je n = 1, 2, 4. Pragmapack vam omogućava da utičete na pakovanje susednih elemenata u strukturama i spojevima (pogledajte Poglavlje 14).

Dogovor bi mogao biti ovakav:

paket (1) - poravnanje elemenata na granicama bajtova;

paket (2) - poravnanje elemenata na granicama riječi;

paket (4) - poravnanje elemenata na granicama dvostrukih riječi;

Neki prevodioci uključuju pragme koje vam omogućavaju da promijenite način na koji se parametri prosljeđuju funkcijama, redoslijed kojim se parametri guraju u stog, itd.

Ugrađeni nazivi makroa

Postoje ugrađeni (predefinisani) nazivi makroa koji su dostupni pretprocesoru tokom obrade. Oni pružaju sljedeće informacije:

DATE__ je niz znakova u formatu: "mjesec dan godina", specificirajući datum kada je počela obrada izvorne datoteke. Na primjer, nakon prethodne obrade teksta programa izvršenog 29. januara 2005. godine, operator

printf (__ DATUM__);

postaće ovako

printf ("% s", "29. januar 2005");

LINE__ je decimalna konstanta - broj trenutno obrađene linije datoteke sa NAS programom. Pretpostavlja se da je broj prvog reda izvornog fajla 1;

FILE__ -niz znakova - naziv kompajlirane datoteke. Ime se mijenja kad god predprocesor naiđe na direktivu # include s imenom druge datoteke. Kada se datoteka uključuje pomoću naredbe #include završi, vraća se prethodna vrijednost imena makroa.

TIME__ je niz znakova u obliku "sati: minute: sekunde", koji definira vrijeme kada pretprocesor počinje obraditi izvorni fajl;

STDC__ je konstanta jednaka 1 ako kompajler radi prema ANSI standardu. Inače, mikroime __STDC__ je nedefinirano. Standard jezika C pretpostavlja da je ime __STDC__ definirano implementacijom jer je makro __STDC__ nov u standardu. U konkretnim implementacijama, skup predefiniranih imena je mnogo širi. Za više informacija o unaprijed definiranim imenima predprocesora, pogledajte dokumentaciju za vaš konkretan kompajler.

Pažnja! Ako vidite grešku na našoj stranici, odaberite je i pritisnite Ctrl + Enter.

© Nacionalni otvoreni univerzitet "INTUIT", 2012 | www.intuit.ru

www.intuit.ru/studies/professional_skill_improvements/1747/courses/43/print_lecture/663

Uvod

C pretprocesor je makro procesor koji se koristi za obradu izvorne datoteke tokom faze 0 kompilacije. Preprocesor C poziva sam predprocesor, ali se predprocesor može pozvati i autonomno. Preprocesorske direktive su instrukcije napisane u izvornom kodu C programa i namijenjene da ih izvrši C predprocesor.

Preprocesorske direktive se obično koriste da bi se olakšalo modifikovanje izvornih programa i učinilo ih nezavisnijim od posebnosti različitih implementacija C kompajlera, različitih računara i operativnih okruženja. Preprocesorske direktive vam omogućavaju da zamenite lekseme u tekstu programa nekim vrednostima, ubacite sadržaj drugog izvornog fajla u izvorni fajl, sprečite kompilaciju nekog dela izvornog fajla, itd. C preprocesor prepoznaje sljedeće direktive:

#define #else #if #ifndef #line
#elif #endif #ifdef #include #undef

Simbol # mora biti prvi u redu koji sadrži direktivu u MSC SP verziji 4. U MSC SP verziji 5 iu TS TS-u može mu prethoditi razmaka znakova... I u MSC PN iu TS TS, razmaci su dozvoljeni između simbola # i prvog slova direktive.

Neke direktive mogu sadržavati argumente. Direktive se mogu napisati bilo gdje u izvornoj datoteci, ali njihov učinak se proteže samo od tačke u programu gdje su napisane do kraja izvorne datoteke.

Instrukcije kompajlera, ili pragme, su instrukcije napisane u izvornom kodu programa i dizajnirane da kontrolišu radnje C prevodioca u određenim situacijama. Skup instrukcija kompajleru i njihovo značenje se razlikuju za različite kompajlere jezika C, stoga je u odeljku 7.8 opisana samo opšta sintaksa instrukcija za kompajler.

U sistemima programiranja koji se razmatraju, moguće je dobiti međuprogramski tekst nakon što se predprocesor pokrene, prije nego što počne stvarna kompilacija. Zamjene makroa su već izvršene u ovoj datoteci, a svi redovi koji sadrže #define i #undef direktive su zamijenjeni praznim redovima. #include redovi su zamijenjeni sadržajem odgovarajućih uključenih datoteka. Uvjetne direktive kompilacije #if, #elif, #else, #ifdef, #ifndef, #endif su obrađene, a redovi koji ih sadrže zamijenjeni su praznim redovima. Fragmenti izvornog teksta koji su bili isključeni tokom uslovne kompilacije takođe su zamenjeni praznim redovima. Osim toga, ova datoteka sadrži redove sljedećeg oblika:

#["Ime dokumenta"]

koje odgovaraju točkama promjene trenutnog broja reda i/ili broja datoteke prema #line ili #include direktivama.

Imenovane konstante i makroi

Direktiva #define se obično koristi za zamjenu uobičajenih konstanti, ključnih riječi, operatora i izraza smislenim identifikatorima. Identifikatori koji zamjenjuju numeričke ili tekstualne konstante, ili proizvoljan niz znakova nazivaju se imenovane konstante. Identifikatori koji predstavljaju određeni niz akcija specificiranih operatorima ili izrazima jezika C nazivaju se makroi. Makroi mogu uzeti argumente. Pozivanje makroa u programu naziva se makro poziv.

U jeziku C uobičajeno je pisati identifikatore imenovanih konstanti i makroa velikim slovima kako bi se razlikovali od imena varijabli i funkcija. To, međutim, nije zahtjev jezika C.

Direktiva #undef nadjačava trenutnu definiciju imenovane konstante. Samo kada se definicija poništi, druga vrijednost se može preslikati na imenovanu konstantu. Međutim, ponavljanje definicije s istom vrijednošću više puta ne smatra se greškom.

Makro definicija liči na definiciju funkcije u sintaksi. Međutim, zamjena poziva funkcije pozivom makroa može povećati brzinu izvršavanja programa, budući da makro definicija ne zahtijeva generiranje sekvence poziva, što traje relativno dugo (guranje argumenata u stek, prijenos kontrole, itd.). S druge strane, ponovljena upotreba makro definicije u programu može zahtijevati mnogo više memorije od poziva funkcija (kod za funkciju se generira jednom, a za makro definiciju - onoliko puta koliko ima poziva makroa u programu) .

Moguće je specificirati definicije imenovanih konstanti ne samo u izvornom tekstu, već iu komandna linija kompilacija.

Postoji niz unaprijed definiranih identifikatora koji se ne mogu koristiti kao identifikatori u direktivama #define i #undef. O njima se govori u Odjeljku 7.9 Pseudovarijable.

#Defini direktivu

sintaksa:

Direktiva #define zamjenjuje sva pojavljivanja u izvornoj datoteci onom koja slijedi u direktivi. Ovaj proces se naziva zamjena makroa i zamjenjuje se samo ako je poseban token. Na primjer, ako je dio niza ili duži identifikator, ne zamjenjuje se. Ako se slijedi, direktiva definira makro s argumentima.

je kolekcija tokena kao što je ključne riječi, konstante, identifikatori ili izrazi. Jedan ili više znakova razmaka moraju biti odvojeni od (ili od parametara zatvorenih u zagradama). Ako tekst ne stane u red, onda se može nastaviti na sljedeći red; da biste to uradili, otkucajte obrnutu kosu crtu na kraju reda i pritisnite taster ENTER odmah iza nje.

može se izostaviti. U tom slučaju, sve instance će biti uklonjene iz izvornog koda programa. Međutim, ona se sama tretira kao što je definirana i kada se provjeri s #if direktivom daje vrijednost 1 (pogledajte odjeljak 7.4.1).

Ako je navedeno, sadrži jedan ili više identifikatora, odvojenih zarezima. Identifikatori na listi moraju se međusobno razlikovati. Njihov opseg je ograničen makro definicijom u kojoj su definisani. Lista mora biti zatvorena u zagradama. Imena formalnih parametara označavaju pozicije na kojima treba zamijeniti stvarne argumente makro poziva. Svako ime formalnog parametra može se pojaviti proizvoljan broj puta.

U pozivu makroa, nakon čega slijedi lista stvarnih argumenata u zagradama koji odgovaraju formalnim parametrima iz. se mijenja zamjenom svakog formalnog parametra odgovarajućim stvarnim argumentom. Liste stvarnih argumenata i formalnih parametara moraju sadržavati isti broj elemenata.

Bilješka. Zamjenu argumenata u makronaredbi ne treba brkati sa prosljeđivanjem argumenata funkciji. Zamjena u pretprocesoru je čisto tekstualne prirode. Ne vrši se nikakvo izračunavanje ili konverzija tipa.

Kao što je gore spomenuto, makro definicija može sadržavati više od jednog pojavljivanja datog formalnog parametra. Ako je formalni parametar predstavljen izrazom s nuspojavom, tada će se ovaj izraz evaluirati više puta, a uz njega će se svaki put pojaviti i nuspojava. U ovom slučaju, rezultat izvršenja može biti pogrešan.

Imena drugih makroa ili konstanti mogu biti ugniježđena unutar #define direktive. Oni se proširuju samo kada se ovo proširuje, a ne kada je definirano s #define direktivom. Ovo treba posebno uzeti u obzir prilikom interakcije ugniježđenih imenovanih konstanti i makroa sa #undef direktivom: do trenutka kada se tekst koji ih sadrži proširi, oni su možda već bili poništeni direktivom #undef.

Nakon što se izvrši zamjena makroa, rezultirajući niz se ponovo skenira kako bi se pronašla druga imena konstanti i definicije makroa. Naziv prethodno izvršene makro supstitucije se ne uzima u obzir prilikom ponovnog pregleda. Stoga direktiva

neće uzrokovati petlju pretprocesora.

/ * primjer 1 * /

#define WIDTH 80

#define DUŽINA (ŠIRINA + 10)

/ * primjer 2 * /

#define FILEMESSAGE "Pokušaj kreiranja fajla \

nije uspio zbog nedovoljnog prostora na disku "

/ * primjer 3 * /

#defini REG1 registar

#defini REG2 registar

/ * primjer 4 * /

#define MAX (x, y) ((x)> (y))? (x): (y)

/ * primjer 5 * /

#define MULT (a, b) ((a) * (b))

U prvom primjeru, WIDTH je definirana kao cjelobrojna konstanta s vrijednošću 80, a LENGTH je definirana kao tekst (WIDTH + 10). Svako pojavljivanje identifikatora DUŽINA u originalnoj datoteci bit će zamijenjeno tekstom (ŠIRINA + 10), koji nakon proširenja identifikatora WIDTH postaje izraz (80 + 10). Zagrade koje okružuju tekst (WIDTH + 10) izbjegavaju greške u izjavama kao što su sljedeće:

var = DUŽINA * 20;

Nakon obrade od strane pretprocesora, operater će uzeti obrazac:

var = (80 + 10) * 20;

Vrijednost koja je dodijeljena var je 1800. Bez zagrada u makro definiciji, izjava bi izgledala ovako:

var = 80 + 10 * 20;

Var bi bio 280 jer množenje ima prednost nad sabiranjem.

Drugi primjer definira identifikator FILEMESSAGE. Njegova definicija se nastavlja na drugi red korištenjem obrnute kose crte neposredno prije pritiska na ENTER.

U trećem primjeru definirana su tri identifikatora, REG1, REG2, REG3. Identifikatori REG1 i REG2 definirani su kao ključne riječi registra. Definicija REG3 je izostavljena i stoga će svako pojavljivanje REG3 biti uklonjeno iz izvorne datoteke. Odjeljak 7.4.1 daje primjer koji pokazuje kako se ove direktive mogu koristiti za postavljanje klase registarske memorije na najvažnije programske varijable.

Četvrti primjer definira MAX makro. Svako pojavljivanje MAX identifikatora u izvornoj datoteci zamjenjuje se izrazom ((x)> (y))?(X) :( y), u kojem se stvarni parametri zamjenjuju formalnim parametrima x i y. Na primjer, makro poziv

će biti zamijenjen izrazom

((1)>(2))?(1):(2)

i makro poziv

će biti zamijenjen izrazom

((i)> (s (i]))? (i) :( s (i])

Imajte na umu da u ovoj makro definiciji argumenti sa nuspojavama mogu proizvesti netačne rezultate. Na primjer, makro poziv

će biti zamijenjen izrazom

((i)> (s))? (i) :( s)

Operandi od> mogu se evaluirati bilo kojim redoslijedom, a vrijednost i ovisi o redoslijedu evaluacije. Stoga je rezultat izraza nepredvidiv. Osim toga, moguće je da će varijabla i biti uvećana dva puta, što vjerovatno nije potrebno.

Peti primjer definira makro definiciju MULT. Makro poziv MULT (3,5) u tekstu programa zamijenjen je sa (3) * (5). Okrugle zagrade, u kojem su stvarni argumenti zatvoreni, neophodni su u slučajevima kada su argumenti makro definicije složeni izrazi. Na primjer, makro poziv

se zamjenjuje sa (3 + 4) * (5 + 6), što je jednako 76. Bez zagrada, rezultat zamjene 3 + 4 * 5 + 6 bi bio 29.

Lepljenje leksema i pretvaranje makro argumenata

JV TS i verzija 5.0 JV MSC implementiraju dvije posebne predprocesorske operacije: ## i #.

U direktivi #define, dva tokena mogu biti "zalijepljena" zajedno. Da biste to učinili, razdvojite ih znakovima ## (razmaci su dozvoljeni lijevo i desno od ##). Predprocesor kombinuje takve tokene u jedan; npr. makroi

#define VAR (i, j) i ## j

sa makro pozivom VAR (x, 6) formira identifikator x6. Neki prevodioci vam dozvoljavaju da koristite oznaku x / ** / 6 u slične svrhe, ali ova metoda je manje prenosiva.

Znak # koji prethodi argumentu makroa označava da se mora konvertovati u niz znakova. Tokom makro poziva, konstrukcija # se zamjenjuje sa "".

Primer: TRACE makro vam omogućava da štampate koristeći standard printf funkcije značenje varijable tipa int u formatu =.

#define TRACE (zastava) printf (#flag "=% d \ n", zastavica)

Sljedeći fragment teksta programa:

TRACE (highval);

nakon obrade od strane pretprocesora poprimiće oblik:

printf ("highval" "=% d \ n", highval);

Sljedeće znakovne nizove C kompajler u MSC verziji 5 SP i u TS TS-u smatra jednom linijom, tako da je rezultujući zapis ekvivalentan sljedećem:

printf ("highval =% d \ n", highval);

Tokom makro poziva, prvo se vrši makro zamjena svih argumenata makro poziva, a zatim njihova zamjena u tijelo makro definicije. Stoga će sljedeći program ispisati redak "odstupanje od standarda":

#define AB "standard"

#define "odstupanje"

#defini B "od standarda"

#define CONCAT (P, Q) P ## Q

printf (CONCAT (A, B) "\ n");

#Undef direktiva

sintaksa:

Direktiva #undef nadjačava trenutni #define for. Da biste poništili definiciju makroa pomoću #undef direktive, dovoljno je da je postavite. Postavljanje liste parametara nije potrebno.

Nije greška primijeniti #undef direktivu na identifikator koji nije prethodno definiran (ili je radnja njegove definicije već otkazana). Ovo se može koristiti da se osigura da je identifikator nedefiniran.

Direktiva #undef se obično koristi u sprezi sa #define direktivom za kreiranje opsega originalni program u kojoj je definiran neki identifikator.

#define WIDTH 80

#define DODAJ (X, Y) (X) + (Y)

U ovom primjeru, #undef direktiva nadjačava definiciju imenovane konstante WIDTH i makro ADD. Imajte na umu da je samo identifikator specificiran za poništavanje makronaredbe.

Uključujući fajlove

sintaksa:

#include "pathname"

Direktiva #include uključuje sadržaj specificirane izvorne datoteke u trenutno prevedenu izvornu datoteku. Na primjer, definicije imenovanih konstanti i makroi koji su zajednički za više izvornih datoteka mogu se sakupiti u jednu datoteku uključivanja i #include u sve izvorne datoteke. Include datoteke se također koriste za pohranjivanje deklaracija vanjskih varijabli i apstraktne vrste podaci koje dijele više izvornih datoteka.

Predprocesor obrađuje uključenu datoteku na isti način kao da je cijela datoteka uključena u izvornu datoteku na mjestu gdje je napisana direktiva #include. Uključeni tekst također može sadržavati direktive pretprocesora. Predprocesor obrađuje uključenu datoteku i zatim se vraća na obradu originalne izvorne datoteke.

Ime putanje je ime datoteke, kojem može prethoditi naziv uređaja i specifikacija direktorija. Sintaksa imena putanje određena je konvencijama operativnog sistema.

Predprocesor koristi koncept standardnih direktorija da pronađe uključene datoteke. Standardni direktoriji su specificirani putem PATH naredbe operativnog sistema.

Predprocesor pretražuje sve dok ne pronađe datoteku sa dato ime.

Ako je ime putanje nedvosmisleno (potpuno) i zatvoreno je u dvostruki navodnici, tada predprocesor traži datoteku samo u direktoriju specificiranom datim imenom putanje i zanemaruje standardne direktorije.

Ako se navedena specifikacija ne formira puno ime putu, predprocesor počinje da traži uključenu datoteku u trenutnom radnom direktorijumu (to jest, u direktorijumu koji sadrži izvorni fajl u koji je upisana direktiva #include).

Direktiva #include može biti ugniježđena. To znači da se može naći u datoteci uključenoj drugom #include direktivom. Kada pretprocesor naiđe na ugniježđenu direktivu #include, počinje tražiti datoteku u trenutnom direktoriju koji odgovara izvornom fajlu koji sadrži tu ugniježđenu direktivu #include. Predprocesor zatim nastavlja s pretraživanjem u trenutnom direktoriju koji odgovara priloženoj izvornoj datoteci, tj. onaj u odnosu na koji je data direktiva #include ugniježđena. Prihvatljiv nivo Ugniježđenje #include direktiva ovisi o implementaciji kompajlera. Proces pretraživanja u direktorijumima koji okružuju se nastavlja sve dok se ne pretraži trenutni direktorij prve izvorne datoteke, odnosno datoteke čije je ime specificirano kada je C kompajler pozvan.

Predprocesor zatim nastavlja da pretražuje direktorijume navedene na komandnoj liniji kompilacije i konačno pretražuje standardne direktorijume.

Ako je ime staze zatvoreno u uglastim zagradama, tada predprocesor uopće neće pretraživati ​​trenutni radni direktorij, već će odmah početi tražiti u direktorijima navedenim u komandnoj liniji kompilacije, a zatim u standardnim direktorijima.

#include / * primjer 1 * /

#include "defs.h" / * primjer 2 * /

Prvi primjer uključuje datoteku pod nazivom stdio.h u izvornoj datoteci. Ugaone zagrade govore predprocesoru da traži datoteku u direktoriju navedenom u komandnoj liniji kompilacije, a zatim u standardnim direktorijima.

Drugi primjer uključuje datoteku pod nazivom defs.h u izvornoj datoteci. Dvostruki navodniki znače da prilikom traženja datoteke prvo se mora pretražiti direktorij koji sadrži trenutni izvorni fajl.

U TS TS-u, moguće je postaviti ime staze u direktivi #include koristeći imenovanu konstantu. Ako identifikator slijedi uključenu riječ, predprocesor provjerava da li imenuje konstantu ili makro. Ako iza riječi uključuje niz navoda ili ugaonih zagrada, TS TS neće tražiti ime konstante u njoj.

#define myinclude "c: \ tc \ include \ mystuff.h"

#include myinclude

#include "myinclude.h"

Prva #include direktiva će uzrokovati da pretprocesor traži u direktoriju C: \ TC \ INCLUDE \ MYSTUFF.H, a druga će ga natjerati da traži datoteku MYINCLUDE.H u trenutnom direktoriju.

Ne možete koristiti konkatenaciju nizova znakova i konkatenaciju tokena u imenovanoj konstanti koja se koristi u direktivi #include. Rezultat proširenja konstante treba odmah pročitati kao važeću direktivu #include.

Uslovna kompilacija

Ovaj odjeljak opisuje direktive koje kontroliraju uvjetnu kompilaciju. Ove direktive vam omogućavaju da isključite sve dijelove izvorne datoteke iz procesa kompilacije provjeravanjem uslova (konstantnih izraza).

#If, #elif, #else, #endif direktive

sintaksa:

Direktiva #if, zajedno sa direktivama #elif, #else i #endif, kontrolira kompilaciju dijelova izvorne datoteke. Svaka #if direktiva u istoj izvornoj datoteci mora imati završnu #endif direktivu. Između direktiva #if i #endif dozvoljen je proizvoljan broj #elif direktiva (uključujući nijednu) i ne više od jedne #else direktive. Ako je prisutna direktiva #else, onda između nje i direktive #endif uključeno ovom nivou nijedna druga #elif direktiva ne bi trebala biti ugniježđena.

Pretprocesor bira jedno od područja za obradu. može obuhvatiti više od jedne linije. Ovo je obično stranica tekst programa, međutim, to nije neophodno: pretprocesor se može koristiti za obradu slobodan tekst... Ako sadrži direktive pretprocesora (uključujući direktive uslovne kompilacije), tada se te direktive izvršavaju. Tekst koji obrađuje pretprocesor prosljeđuje se kompilaciji.

Dio teksta koji nije odabran od strane pretprocesora zanemaruje se u fazi pretprocesiranja i ne kompajlira se.

Predprocesor odabire komad teksta za obradu na osnovu izračuna nakon svake #if ili #elif direktive. Odabrano nakon true (nenula), do najbliže #elif, #else ili #endif direktive povezane s ovom #if direktivom.

Ako nijedan ograničeni konstantni izraz nije istinit, tada predprocesor odabire onaj koji slijedi direktivu #else. Ako je direktiva #else odsutna, tekst nije odabran.

Ograničeni konstantni izraz opisan je u Odjeljku 4.2.9 "Konstantni izrazi". Takav izraz ne može sadržavati veličinu operacije (u TS TS-u može), operaciju konverzije tipa, konstante nabrajanja i plutajuće konstante, ali može sadržavati definiranu () operaciju pretprocesora. Ova operacija daje istinito (ne jednak nuli) vrijednost, ako je definirana trenutno data; u suprotnom, izraz je netačan (jednak nuli). Treba imati na umu da se identifikator definiran bez vrijednosti i dalje smatra definitivnim. Definirana operacija se može koristiti u složen izraz u #if direktivi više puta:

#ako je definirano (mysym) || definirano (vas sim)

SP TC (za razliku od SP MSC) dozvoljava korištenje sizeof operacije u ograničenom konstantnom izrazu za predprocesor. V sljedeći primjer ovisno o veličini pokazivača, definira se jedna od konstanti - SDATA ili LDATA:

#if (sizeof (void *) == 2)

#Ako direktive mogu biti ugniježđene. Štaviše, svaka od #else, #elif, #endif direktiva je povezana s najbližom prethodnom #if direktivom.

/ * primjer 1 * /

#ako je definirano (KREDIT)

#elif definiran (DEBIT)

/ * primjer 2 * /

#define SIGNAL 1

#ako STACKUSE == 1

#derine STACK 200

#define STACK 100

#define SIGNAL 0

#ako STACKUSE == 1

#define STACK 100

#define STACK 50

/ * primjer 3 * /

#elif DLEVEL == 1

#define STACK 100

#elif DLEVEL> 5

prikaz (debugptr);

#define STACK 200

/ * primjer 4 * /

#define REG 1 registar

#defini REG2 registar

#ako je definirano (M_86)

#ifdefined (M_68000)

#define REG4 registar

U prvom primjeru, direktive #if, #elif, #else, #endif kontroliraju kompilaciju jednog od tri poziva funkcije. Poziv na kredit se kompajlira ako je definirana imenovana konstanta CREDIT. Ako je imenovana konstanta DEBIT definirana, tada se kompajlira poziv funkcije zaduženja. Ako nijedna od imenovanih konstanti nije definirana, onda se kompajlira poziv funkcije printera. Imajte na umu da su KREDIT i kredit različiti identifikatori u jeziku C.

Sljedeća dva primjera pretpostavljaju da je DLEVEL konstanta unaprijed definirana direktivom #define.

Drugi primjer pokazuje dva ugniježđena skupa #if, #else, #endif direktiva. Prvi skup direktiva se obrađuje ako je vrijednost DLEVEL veća od 5. U suprotnom, drugi skup se obrađuje.

U trećem primjeru, privlačne direktive kompilacije koriste vrijednost DLEVEL konstante za odabir teksta. STACK konstanta je definirana vrijednošću 0, 100 ili 200, ovisno o vrijednosti DLEVEL. Ako je DLEVEL veći od 5, tada se kompajlira poziv za prikaz, a STACK konstanta nije definirana.

U četvrtom primjeru, predprocesorske direktive se koriste za kontrolu primjene specifikacije klase registarske memorije u programu dizajniranom za rad u različitim operativnim okruženjima.

Kompajler će obično istaknuti registar memorija varijable redoslijedom kojim su deklaracije varijabli napisane u programu. Ako program sadrži više deklaracija varijabli registra memorijske klase nego što ima registara u datom operativno okruženje, tada će samo one varijable čije su deklaracije napisane ranije dobiti registarsku memoriju. Stoga, ako intenzivnije koristite one varijable koje su kasnije deklarirane, dobitak efikasnosti od korištenja registara će biti zanemarljiv.

Primjer pokazuje kako dati prioritet registarskoj memoriji za najvažnije varijable. Imenovane konstante REG1 i REG2 definirane su kao ključne riječi registra. Namjera im je da proglase dva najvažnija lokalna funkcijske varijable... Na primjer, u sljedećem isječku koda, ove varijable su b i c.

funkcija (REG3 int a)

Ako je konstanta M_86 definirana, predprocesor uklanja REG3 i REG4 identifikatore iz datoteke zamjenjujući ih sa prazan tekst... U ovom slučaju, samo varijable b i c će dobiti registarsku memoriju. Ako je identifikator M_68000 definiran, tada su sve četiri varijable deklarirane s klasom memorije registra.

Ako nijedna od konstanti nije definirana - ni M_86, ni M_68000 - tada će registarska memorija primiti varijable a, b i c.

#Ifdef i #ifndef direktive

sintaksa:

Slično #if direktivi, #ifdef i #ifndef direktive mogu biti praćene skupom #elif direktiva i #else direktive. Skup mora biti dovršen s #endif direktivom.

Upotreba #ifdef i #ifndef direktiva je ekvivalentna upotrebi #if direktive pomoću izraza s definiranim () operatorom. Ove direktive se održavaju isključivo radi kompatibilnosti sa prethodne verzije C kompajleri. Za nove programe preporučuje se korištenje #if direktive s definiranom () operacijom.

Kada predprocesor obradi #ifdef direktivu, provjerava da li je trenutno definirana direktivom #define. Ako da, uslov se smatra tačnim, ako nije, netačnim.

Direktiva #line se obično koristi automatski generatori programe tako da se dijagnostičke poruke ne odnose na izvornu datoteku, već na generirani program.

u direktivi #line može biti proizvoljna cjelobrojna konstanta. može biti proizvoljna kombinacija znakova, zatvorena u dvostruke navodnike. Ako je naziv datoteke izostavljen, originalni naziv datoteke ostaje isti.

Trenutni broj linije i naziv izvorne datoteke dostupni su u programu preko pseudo-varijabli pod nazivom __LINE__ i __FILE__. Ove pseudo-varijable se mogu koristiti za izdavanje poruka o izvršavanju tacna lokacija greške.

Vrijednost pseudo-varijable __FILE__ je niz koji predstavlja ime datoteke, zatvoren u dvostruke navodnike. Stoga, ne morate staviti sam identifikator __FILE__ u dvostruke navodnike da biste ispisali naziv izvorne datoteke.

/ * primjer 1 * /

#red 151 "copy.c"

/ * primjer 2 * /

#define ASSERT (cond) if (! cond) \

(printf ("greška u redu% d datoteke% s \ n", \

LINE__, __FILE__);) else;

Prvi primjer postavlja naziv izvorne datoteke coop.c i trenutni broj reda na 151.

Drugi primjer koristi pseudo-varijable __LINE__ i __FILE__ u ASSERT makrou za ispis poruke o grešci koja sadrži koordinate izvorne datoteke ako je neki uvjet specificiran argumentom cond makroa netačan.

Direktiva za rukovanje greškom

TS TS je implementirao direktivu #error. Njegov format:

Obično je ova direktiva napisana među direktivama uslovne kompilacije za otkrivanje neke nezakonite situacije. Po #error direktivi, predprocesor prekida kompilaciju i prikazuje sljedeću poruku:

Fatalno: Direktiva o grešci:

Fatalno je znak fatalna greska; - naziv izvorne datoteke; - broj tekućeg reda; Direktiva o grešci - poruka o grešci u direktivi; - stvarni tekst dijagnostičke poruke.

Upute do C kompajlera

sintaksa:

Nagoveštaji kompajlera ili pragme su namenjeni da ih prevodilac izvršava dok je pokrenut. specificira specifičnu instrukciju kompajleru i eventualno argumente.

Skup pragma za svaki C kompajler je drugačiji. Za detalje o pragmama, pogledajte sistemsku dokumentaciju za kompajler koji koristite.

Pseudo-varijable

Pseudo-varijable su rezervirane imenovane konstante koje se mogu koristiti u bilo kojoj izvornoj datoteci. Svaki od njih počinje i završava s dvije donje crte (__).

Trenutni broj reda izvorne datoteke koja se obrađuje je decimalna konstanta. Prvi red izvorne datoteke označen je brojem 1.

Ime kompajlirane izvorne datoteke je niz znakova. Vrijednost ove pseudo-varijable se mijenja svaki put kada kompajler obradi direktivu #include ili #line direktivu, kao i nakon što se uključi datoteka završi.

Sljedeće dvije pseudo-varijable podržava samo TS TS.

Datum kompilacije trenutne izvorne datoteke je niz znakova. Svako pojavljivanje __DATE__ in dati fajl daje istu vrijednost, bez obzira koliko dugo obrada traje. Datum ima format mmm dd UUUU, gdje je mmm mjesec (jan, februar, mar, april, maj, jun, jul, avgust, septembar, oktobar, novembar, decembar), dd je dan tekućeg mjeseca (1 ... 31; na 1- prva pozicija dd je razmak ako je broj manji od 10), yyyy - godina (npr. 1990).

Vrijeme kompilacije trenutne izvorne datoteke je niz znakova. Svako pojavljivanje __TIME__ u datoj datoteci daje istu vrijednost, bez obzira koliko dugo obrada traje. Vrijeme ima format hh:mm:ss, gdje je hh sat (00…23), mm su minute (00…59), ss sekunde (00…59).

Top srodni članci