Sunteți pe pagina 1din 7

CURS 8 Tipul enumerare, linii de comand pentru compilator

8.1. Enumerri
O enumerare este un set de constante care specific toate valorile permise pe care le poate avea o variabil de acel tip. Permite utilizatorului s foloseasc n program nume sugestive n locul unor valori numerice. De exemplu n locul numrului unei luni calendaristice se poate folosi denumirea ei sau n loc de 0 i 1 se poate folosi ADEVRAT sau FALS. Formatul general de declarare a unei enumerri este: enum nume_generic {lista enumerrilor} lista_variabile_enumerare; constantele pot avea specificate valori (i o valoare se poate repeta) enum luni_curs {ian=1, feb, mar, apr, mai, iun, oct=10, nov, dec}; implicit, irul valorilor e cresctor cu pasul 1, iar prima valoare e 0 un nume de constant nu poate fi folosit n mai multe enumerri tipurile enumerare sunt tipuri ntregi, variabilele enumerare se pot folosi la fel ca variabilele ntregi cod mai lizibil dect prin declararea separat de constante enum {D, L, Ma, Mc, J, V, S} zi; // tip anonim; declar doar variabil zi // tipul nu are nume , nu mai putem declara altundeva variabilele int nr_ore_lucru[7]; // numr de ore pe zi for (zi = L; zi <= V; ++zi) nr_ore_lucru[zi] = 8; enum curcubeu {rou, orange, galben, verde, albastru, indigo, violet}; enum curcubeu ec; printf(%d %d\n, rou, verde); //va afia 0 3. Asupra unei variabile enumerare se pot face atribuiri: ec=albastru; sau valoarea lor poate fi comparat cu una din valorile din enumerare: if (ec==albastru) printf(Albastru!\n); Pentru a specifica valoarea unuia sau mai multor simboluri putem folosi iniializri. Simbolurilor care apar dup iniializare li se atribuie automat valori ce urmeaz dup acea valoare. enum curcubeu {rou, orange, galben=100, verde, violet} ec; printf(%d %d\n, verde,violet); //va afia 101 104. albastru, indigo,

Exemplu1:
typedef enum {verde, galben,rosu} culoare; culoare semafor; semafor=galben;
1

...... switch(semafor){ case verde:libera_trecere();break; case galben: asteapta();break; case rosu: oprire_motor();break; default: semafor_inactiv() } Exemplu2: #include <stdio.h> enum culori {ROSU, GALBEN, VERDE, ALBASTRU, VIOLET, NUMAR_CULORI} typedef enum culori TCuloare; int main (void) { TCuloare cer, padure; printf(In enum sunt %d culori\n,NUMAR_CULORI); cer=ALABSTRU; padure=VERDE; printf(cer=%d\n,int cer); printf(padure=%d\n,int padure); return 0; } In mod natural, diferitele tipuri definite de utilizator pot fi combinate, astfel nct putem avea de exemplu tablouri de structuri sau invers, tablouri ale caror elemente sunt enumerri. Pentru a evita declaraii de genul struct node x,y,z sau enum boolean s,b; limbajul C furnizeaz mecanismul de definire a numelui de tipuri cu ajutorul lui typedef. Acesta creeaz tipuri sinonime cu cele denumite i care pot fi utilizate n declaraii de variabile, mrind claritatea programului. Este sugestiv definirea n programul anterior a tipului TCuloare i utilizarea lui n programul principal n locul tipului enum culori.

8.2. Linii de comand pentru compilator


Compilatorul C conine un preprocesor capabil s fac substituii lexicale, macroinstruciuni, compilri condiionate i includeri de fiiere. Prepocesorul execut operaii anterioare compilrii propriu-zise, operaii ce sunt specificate prin directive preprocesor. Preprocesorul este apelat automat nainte de a ncepe compilarea. Preprocesorul limbajului C este relativ simplu i el, n principiu, execut substituii de texte. Prin intermediul lui se pot realiza: - Includeri de texte; - Definiii i apeluri de macrouri simple; - Compilare condiionata. Acestea au ntotdeauna ca i prim caracter simbolul # i permit efectuarea de manipulri n textul programului surs naintea compilrii sale. Liniile care ncep cu simbolul # au o sintax independent de restul limbajului, pot aprea oriunde n cadrul programului surs (dar se recomand plasarea la nceputul lui) i au efecte cu remanen pn la sfritul execuiei programului sau pn cnd o nou directiv anuleaz acest lucru. Fiecare din directivele preprocesor trebuie s se gseasc pe o linie separat.
2

Substituia lexical se face prin directiva: #define identificator [text] Dac identificatorul este recunoscut ca element lexical n analiza programului surs, preprocesorul va nlocui toate apariiile ulterioare ale identificatorului cu secvena text precizat. Dac textul trebuie s se extind pe mai multe linii, liniile intermediare vor fi precedate de un caracter \. Textul poate fi i vid ceea ce va avea ca i efect suprimarea din textul surs a tuturor apariiilor identificatorului. Pentru a distinge mai uor identificatorul substituit, se recomand folosirea majusculelor. Exemple: #define #define #define #define #define

void //suprimarea din textul surs a tuturor apariiilor identificatorului void then //suprimarea tututor apariiilor identificatorului then begin { //nlocuirea identificatorului begin cu { end } // nlocuirea identificatorului end cu } N 100 //nlocuiete identificatorul N cu valoarea 100

O dat fcut o substituie lexical, ea poate fi folosit ca parte a unei alte substituii lexicale. Astfel, avnd ultima substituie lexical din exemplul precedent, este corect s scriem: #define NPATRAT N*N Un identificator care a apare deja ntr-o linie #define poate fi ulterior redefinit ulterior n program cu o alt linie #define. Preprocesorul va substitui n continuare identificatorul cu noua definiie a lui. Substituirea nu se face n cazul n care identificatorul apare ntre ghilimele, n acest caz el nejucnd practic rolul unui identificator. Exemplu: #define PI 3.14 printf(valoarea lui PI are un numar infinit de zecimale!\n); n acest caz, nu se face expandarea. Macroinstruciuni Sunt substituii cu parametri formali i se realizeaz cu ajutorul directivei: #define identificator(lista_param_formali) text Parametri formali sunt nlocuii de cei din lista parametrilor reali. Nu trebuie s existe nici un spaiu ntre identificator i lista_param_formali. Exemple:
3

#define max(a,b) (a)>(b)?(a):(b) #define abs(a) (a)<0?-(a):(a) Se obine o scriere asemntoare unui apel de funcie dar care este tratat mai direct prin nlocuire n textul surs i nu printr-un apel de funcie ceea ce este mai avantajos din punct de vedere al performanelor de vitez. Macroinstruciunile se execut mai repede dect funciile lor echivalente deoarece compilatorul nu necesit depunerea pe stiv a parametrilor i apoi returnarea valorilor. Avnd n vedere c macroinstruciunile mresc dimensiunea codului, este indicat a ne limita doar la calcule simple pentru a nu crete talia programului. Se remarc utilizarea parantezelor rotunde la ncadrarea parametrilor formali. Dac acestea sunt omise, evaluarea se poate face eronat dac parametri formali sunt substituii de expresii. Exemplu: #include<stdio.h> #define PAR(a) a%2==0?1:0 //ncercm folosirea macroinstruciunii fr paranteze rotunde void main(void) { if PAR(9+1)) printf(este par\n); else printf(este impar\n); } Efectul utilizrii n acest mod a macroinstruciunii este eronat deoarece: 9+1%2= =0 va conduce la 9+0 = =0 adic fals ceea ce va genera mesajul este impar n loc s obinem mesajul este par. Cauza este lipsa parantezelor la definirea macroinstruciunii. Utilizarea sub forma: #define PAR(a) (a)%2= = 0?1:0 va conduce spre un rezultat corect deoarece: (9+1)%2= = 0 conduce spre 0 = = 0 ceea ce este adevrat iar mesajul generat va fi este par. Funcii din biblioteci standard pot fi implementate sub form de macroinstruciuni: #define _tolower(c) ((c)-A+a) #define _toupper(c) ((c) a+A) #define toupper(c) ((islower(c))?_toupper(c):(c)) Prototipurile acestor funcii se gsesc n ctype.h. Textul de substituie se poate ntinde pe mai multe linii folosind caracterul \ la sfritul fiecrei linii pentru care dorim ca textul s continue pe linia urmtoare. Exemplu: define ISCH(TIP, x, y) {\ TIP t;\ t=x;\ x=y;\ y=t;\ } Apelul unui astfel de macrou se face de exemplu sub forma ISCH(int,a,b) i va determina interschimbarea valorilor variabilelor ntregi a i b. Suprimarea unei definiii
4

O definiie fcut cu ajutorul directivei define este valabil pe tot restul modulului care o urmeaz. Dac se dorete suprimarea acestei validiti se folosete directiva: #undef identificator La ntlnirea unei astfel de linii, preprocesorul nu mai expandeaz n continuare macroul cu numele respectiv. Acest lucru este valabil fie pn la sfritul fiierului cu textul surs fie pn la o nou definiie de macrou cu acelai nume. Compilri condiionate Se fac prin directive de forma: #if expresie_constant else #endif Efectul acestei directive este urmtorul: dac expresie_constant este evaluat la o valoare diferit de zero, se compileaz liniile dintre #if i else. n caz contrar, se vor compila liniile dintre else i #endif. Ramura else poate lipsi. Directiva #elif nseamn altfel-dac i este urmat de o expresie constant. Forma general este a acestei directive este: #if expresie1 #elif expresie2 .. #elif expresie3 #elif expresien #endif Dac una din expresii este adevrat, este compilat acel bloc de cod i nici o alt expresie #elif nu mai este testat. Directivele: #ifdef NUME #endif i #ifndef NUME
5

#endif determin compilarea liniilor doar dac NUME a fost definit (deci dac a fost subiectul unei linii #define), respectiv nu a fost definit. Toate aceste construcii pot fi imbricate. Oprirea compilrii se poate face folosind directiva: #error mesaj_eroare Mesajul de eroare nu se delimiteaz prin ghilimele. Aceast directiv este folosit pentru depanare. n momentul ntlnirii unei astfel de directive, se oprete compilarea i se afieaz mesajul de eroare precizat. Includerea fiierelor se face prin una din directivele: #include<nume_fisier> #includenume_fisier Aceast directiv are rolul de a solicita compilatorului ca, in faza de preprocesare, acesta s includ n textul surs n care este folosit aceast directiv, ntregul coninut al fiierului desemnat, cu scopul de a fi compilate mpreun. Este valid prezena unei directive include ntr-un fiier care este apelat la rndul lui printr-o alt directiv include. Standardul ANSI C prevede existena unui numr minim de opt niveluri de includere imbricate. Fiierul este cutat dup cum urmeaz: a)dac fiierul se delimiteaz ntre paranteze unghiulare se va cuta fiierul n directorul specificat de mediul de programare Dac fiierul nu este gsit, se continu cutarea n directoarele standard ale mediului. b) dac fiierul se delimiteaz ntre ghilimele fiierul este cutat: b1)Dac se specific calea ca i parte component a numelui fiierului doar n acel director se va face cutarea. b2)Dac nu se specific calea, fiierul va fi cutat n directorul curent (cel n care am fost n momentul n care am lansat mediul de programare). n loc ca programatorul s foloseasc propriile sale declaraii pentru funciile de bibliotec, se recomand includerea n cadrul programului surs a unor fiiere antet (header), care conin declaraiile funciilor de bibliotec apelate. Aceste fiiere au n general extensia .h i se gsesc n directorul INCLUDE. Includerea fiierelor se folosete pentru gestionarea corect a unui proiect, n general de mari dimensiuni, care se compune din mai multe module. Pentru ncorporarea la nceputul fiecrui modul de de fiiere de descriere se pot crea: -fiiere coninnd definiii generale ale proiectului: declaraii de tip i directive ale preprocesorului, n particular directive define -fiiere coninnd declaraii de variabile externe n cazul n care definirea lor a fost regrupat ntr -un modul special.

Programele C mari pot fi structurate pe mai multe fiiere, care pot fi compilate distinct. Aceasta prezint mai multe avantaje: -n cazul erorilor sintactice i semantice, doar fiierul eronat trebuie recompilat, dup modificrile sau coreciile aduse. Programatorul poate profita de faptul c unitatea de compilare este fiierul, repartiznd funciile programului su n mai multe fiiere. n acest fel, modificarea unei funcii va fi urmat de recompilarea doar a fiierului care o conine i a fiierelor care depind de el, nu a ntregului program, obinndu-se astfel un ctig de timp nsemnat. -structurarea programelor pe mai multe fiiere permite simularea mecanismului de ncapsulare a datelor. Variabilele i funciile avnd clasa de memorare static pot fi accesate doar n cadrul fiierului n care au fost definite. Variabilele i funciile declarate cu clasa de memorare extern sunt definite n alt fiier dect cel curent, dar ele pot fi accesate n fiierul curent. Observaie: Dac se modific un fiier care este inclus printr-o directiv #include, atunci toate fiierele care depind de el trebuie recompilate.