Date post: | 04-Oct-2015 |
Category: |
Documents |
Upload: | alecsandra-rusu |
View: | 65 times |
Download: | 5 times |
CURS 12
PREPROCESAREA N
LIMBAJUL C/C++
CUPRINS
1. Noiuni introductive
2. Includeri de fiiere
3. Definiii de macro-uri
4. Macrodefiniii cu parametri (funcii macro)
5. Compilarea condiionat
6. Alte directive preprocesor
7. Macrouri predefinite
8. Aseriuni
9. Funcii inline
2
1. NOIUNI INTRODUCTIVE
Preprocesorul (pp) execut operaii prealabile compilrii
Pentru aceasta, fiierul iniial este transformat ntr-unul echivalent prin includeri de fiiere, macrodefiniii (macro-uri) i apeluri de macro-uri, compilare condiionat
Directivele pp ncep cu simbolul # (diez) i au forma urmtoare:
# nume_directiva simboluri
un simbol este orice altceva dect un spaiu sau tab
caracterul # trebuie s fie primul caracter ce nu este spaiu sau tab
3
NOIUNI INTRODUCTIVE
Intre caracterul # i directiv pot exista de asemenea spaii sau tab-uri:
#define size 100
# define size 100
# define size 100
Uzual, o directiv pp ocup o singur linie, dar este posibil ca directiva s continue pe mai multe linii folosind caracterul \ pe ultima poziie a liniei ce se continu
Pe aceeai linie cu o directiv poate exista i un comentariu ce va fi ignorat de ctre pp
De asemenea, dac un caracter # izolat apare pe o linie, va fi neglijat 4
2. INCLUDERI DE FIIERE
Se folosesc pentru a include fiiere antet:
ce conin, de obicei, declaraii de constante, variabile i prototipuri de funcii
Se fac cu directive #include
nainte de compilare, se include n textul surs, n poziia curent, coninutul fiierelor antet specificate n directive
Includerea este transparent utilizatorului
5
INCLUDERI DE FIIERE
Forme:
#include
#include "specificator_fisier
Prima variant este folosit pentru a include fiiere antet ale mediului de programare, situate n anumite directoare specificate n setrile mediului
A doua variant este folosit pentru a include fiiere antet proprii, situate n directorul curent sau n alt parte, caz n care se specific i calea
6
INCLUDERI DE FIIERE
Exemple:
#include
#include "my_decl.h" // cale relativa director curent
#include "...\\file.h" // directorul parinte, SO Windows
#include "D:/user/local/file.h" // cale completa, orice SO
7
INCLUDERI DE FIIERE
Includerea de fiiere poate fi imbricat:
un fiier include un fiier antet care la rndul lui include alt fiier antet,
Pot aprea conflicte dac exist identificatori cu acelai nume n fiierele incluse cu cei din fiierul curent
8
3. DEFINIII DE MACRO-URI
Se fac cu directiva #define i respectiv #undef
#define nume sir_caractere
#undef nume
Se folosesc pentru a defini constante simbolice sau mai general macrofuncii(dac apar i parametri), respectiv pentru a anula o definire anterioar
Definirea este valabil din punctul n care apare directiva "#define" pn la ntlnirea unei directive "#undef" corespondente sau pn la sfritul fiierului
9
DEFINIII DE MACRO-URI
pp nlocuiete toate apariiile irului "nume" ce urmeaz liniei curente cu irul de caractere asociat n directiv, cu urmtoarele excepii:
n interiorul unei constante caracter sau ir de caractere
n interiorul comentariilor
Inlocuirea se mai numete i expandare
10
DEFINIII DE MACRO-URI
De obicei se folosesc litere mari n "nume" pentru a recunoate mai uor n program constantele simbolice
Intre "nume" i "sir_caractere" pot sa apar mai multe spaii albe (cel puin unul)
Nu se folosete terminatorul ;
dac acesta apare se consider c face parte din irul de substituie
De cele mai multe ori constantele simbolice se folosesc pentru a asocia identificatori unor numere:
ca urmare pot fi urmrite uor n program i pot fi uor modificate (ntr-un singur loc, prin modificarea irului de substituie)
de reinut c nu se face declararea unei constante
Dup o directiv #undef macro-ul poate fi redefinit
11
DEFINIII DE MACRO-URI
Exemple:
#define DIM 100
int tab[DIM];
...
#undef DIM
#define DIM 10
#define CT_CAL 0.1234
x = cit_CAD( ) * CT_CAL
12
DEFINIII DE MACRO-URI
Substituia se aplic i liniilor cu directive pp
ca urmare un identificator definit ntr-o linie poate fi
utilizat n alt directiv #define
se recomand folosirea parantezelor pentru evitarea ambiguitilor ce pot conduce la efecte nedorite:
#define MIN 1
#define MAX MIN + 100
...
rez = 10*MAX; // rez = 10*MIN + 100
#define MAX (MIN + 100)
rez = 10*MAX; // rez = 10*(MIN + 100) 13
DEFINIII DE MACRO-URI
Dac irul de caractere (corpul macroului) este un ir vid atunci se obine tergerea identificatorului din codul surs
O macrodefiniie nu va fi expandat n timpul propriei expandri, adic nu se ajunge la o expandare infinit:
#define A A
14
DEFINIII DE MACRO-URI
Utilizarea constantelor simbolice este specific limbajului C, limbaj n care nu se pot defini constante
In limbajul C++, prin folosirea modificatorului const, se
pot folosi constante i se beneficiaz de verificrile de tip fcute de compilator
15
DEFINIII DE MACRO-URI
Exemple:
C
#define pi 3.14 - constant fr tip
#define SIZE ROWS*COLS - valoare calculat prin substituie de pp unde ROWS si COLS au fost definite anterior
#define SIZE 200 - eventual avertizare la redefinire
C++
const float pi = 3.14; - constant cu tip
const int SIZE = ROWS*COLS; - valoare calculat de compilator prin evaluarea expresiei unde ROWS i COLS sunt definite in prealabil
//const int SIZE = 200; - redefinire nepermis 16
4. MACRODEFINIII CU PARAMETRI
(FUNCII MACRO)
Sintaxa:
#define nume(p1, p2,...,pn) text
unde:
pi sunt parametri formali
text este textul de substituie care va conine parametrii formali
poate continua pe mai multe rnduri folosind
caracterul '\ la sfritul fiecrui rnd
17
MACRODEFINIII CU PARAMETRI
Dac parametrii formali lipsesc avem o definiie de constant simbolic
Intre "nume" i prima parantez "(" nu pot exista spaii albe (spatiu simplu, tab):
dac apare acest spaiu, linia este interpretat ca o definire de constant simbolic al crei ir de substituie ncepe cu (
Apelul unei macrodefiniii cu parametri se face analog apelului unei funcii:
numele macro-ului urmat de parametrii efectivi ntre paranteze i separai prin virgule
Parametrii efectivi se substituie parametrilor formali n textul de substituie, iar apoi textul rezultat se substituie apelului
Reprezint primul mecanism generic introdus n limbajul C/C++
18
MACRODEFINIII CU PARAMETRI
Numrul parametrilor efectivi trebuie s coincid cu cel al parametrilor formali
Corespondena dintre parametrii formali i cei efectivi se face prin poziie
Pentru evitarea ambiguitilor se recomand folosirea parantezelor pentru fiecare parametru
Anularea unei macrodefiniii cu parametri se face cu o directiv: #undef nume
este posibil apoi redefinirea macro-ului
19
MACRODEFINIII CU PARAMETRI
Exemple:
1. #define Sqr(a) (a)*(a)
c = Sqr(a-b); // c = (a-b)*(a-b);
#define Sqr(a) a*a
c = Sqr(a-b); // c = a-b*a-b;
2. #define abs(x) (x < 0 ? -x : x)
a = abs(b-c); // a = (b-c < 0 ? b+c : b-c);
#define abs(x) ((x) < 0 ? (-x) : (x))
a = abs(b-c); // a = ((b-c) < 0 ? -(b-c) : (b-c))
3. #define max2(a,b) (((a)>(b)) ? (a) : (b)) 20
MACRODEFINIII CU PARAMETRI
Macrodefiniiile cu parametri se folosesc n cazul n care se folosesc calcule simple, eliminnd apelurile de funcii
Operaii efectuate la apelul unei funcii: transferul parametrilor (de exemplu prin stiv) salvare adres de revenire salt la adresa de nceput a funciei
Operaii ce se execut la revenirea dintr-o funcie: transferul rezultatului
salt la adresa urmtoare apelului refacerea stivei (eliberarea stivei)
21
MACRODEFINIII CU PARAMETRI
Avantaje macrofunctiilor fa de funcii constau n faptul c se evit operaiile de la apelul/revenirea dintr-o funcie:
n unele cazuri aceste operaii pot fi mai "costisitoare" dect calculul nsui
Dezavantaje:
creterea lungimii programelor datorit expandrii nu se fac verificri de tip la apel nu se aplic proprieti legate de domeniu de
valabilitate
nu se pot compila separat
22
MACRODEFINIII CU PARAMETRI
Alte considerente:
-Macrofunciile n general nu returneaz o valoare i de aceea rezultatul este memorat de obicei n unul din parametrii ei
-Putem avea situaii n care macrofuncia ofer un rezultat, mai ales la utilizarea operatorului condiional
-Cuvintele cheie min, max sunt rezervate n unele medii de programare integrate i se genereaz erori la utilizarea lor ca i macro funcii
23
EXEMPLE VARIANTA OPERATOR CONDITIONAL I IF
A) #define MAX2(a,b) ((a)>(b)?(a):(b))
Apel:
cin >>a; cin >>b;
cout>b;
MAX2I(a,b);
cout
5. COMPILAREA CONDIIONAT
Permite ca anumite zone din program s fie incluse sau excluse de la compilare
Se folosete pentru:
obinerea mai multor variante ale aceluiai program
sau pentru creterea portabilitii programelor prin scrierea unui cod pentru anumite platforme hardware
sau software
25
COMPILAREA CONDIIONAT
Directivele: #if, #else, #endif
#if expr_ct
sectiune_1
[#else
sectiune_2]
#endif
Exemplu:
#define O_COND 2
#if (O_COND != 0 && O_COND != 1)
#error O_COND must be 0 or 1
#endif 26
COMPILAREA CONDIIONAT
Se poate genera o structur de selecie generalizat prin folosirea directivelor #elif :
#if expr_ct1 [sectiune_1]
[#elif expr_ct2 sectiune_2]
...
[#elif expr_ctn sectiune_n]
[#else sectiune_finala]
#endif
27
COMPILAREA CONDIIONAT
Directivele #if se folosesc pentru omiterea temporar a unei zone de cod:
de exemplu, n etapa de testare i depanare cnd se fac experimente pe zone de cod suspecte
i cu ajutorul comentariilor pe mai multe linii se pot exclude zone de cod, ns aceste comentarii nu pot fi imbricate
Dac expresia asociat unei directive #if are ntotdeauna valoarea zero, excluderea este asigurat:
#if 0
...cod ce va fi exclus de la compilare
#endif
Altfel, pentru includere avem:
#if 1
...cod ce va fi inclus la compilare
#endif
28
ALTE EXEMPLE
#if !defined(NULL)
#define NULL 0
#endif
-afisare la DEBUG a variabilei x:
#ifdef DEBUG
printf("Variable x = %d\n", x);
#endif
29
COMPILAREA CONDIIONAT
Directivele: #ifdef, #ifndef
#ifdef nume_m #ifndef nume_m
sectiune_1 sectiune_1
[#else [#else
sectiune_2] sectiune_2]
#endif #endif
n aceste construcii nu se pot folosi directive #elif
30
COMPILAREA CONDIIONAT
Operatorul defined: defined(nume_macro)
Are valoarea 1 dac numele a fost definit anterior cu directiva #define i definiia nu a fost anulat cu directiva #undef
Poate fi folosit doar n expresiile asociate directivelor #if i #elif, dar pot fi combinai folosind operatori logici (negaie, and, or)
#ifndef NULL
#if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
#define NULL 0
#else
#define NULL 0L
#endif
#endif
31
COMPILAREA CONDIIONAT
Compilarea condiionat poate fi folosit i pentru a evita includerea multipl a fiierelor antet
n cazul unui fiier antet cu numele file.h se vor folosi urmtoarele directive pp:
#ifndef _FILE_H_
#define _FILE_H_
definire continut fisier file.h
#endif
32
EXEMPLU- HEADER BOOLEAN.H
#ifndef BOOLEAN_H
typedef int boolean; // means literal string 'int' is same as 'boolean'
const boolean FALSE = 0;
const boolean TRUE =1;
#define BOOLEAN_H
#endif
33
#define Module10
#define MyVersion 1.1
#include
using namespace std;
#include "boolean.h"
#include
int main(void){
cout
#ifndef MyVersion
cout
// program using the user defined header file, boolean.h
cout
37
6. ALTE DIRECTIVE PREPROCESOR
#pragma nume_directiva
Permite utilizarea unor directive specifice implementrii Dac directiva specificat nu este recunoscut nu se
genereaz eroare i se trece mai departe Directiva este folosit de furnizorii de compilatoare
pentru a introduce faciliti nestandard ale pp, specifice acelei implementri
Exemplu:
#pragma warn-aus
void LinkFloat (void){
float f=0; *pf=&f;}
#pragma warn-aus
38
ALTE DIRECTIVE PREPROCESOR
#pragma inline
specific faptul c n modulul curent apar instruciuni n limbaj de asamblare
#pragma startup nume-functie
#pragma exit nume-functie
Aceste directive pp permit specificarea unor funcii ce vor fi apelate naintea nceperii execuiei programului (nainte de apelul funciei main()), respectiv nainte de terminarea execuiei programului
Funciile specificate trebuie s aib urmtorul prototip: void func(void);
39
Cuvntul cheie pragma este parte din limbajul C++
standard, dar forma, coninutul i sensul lui pragma este diferit pentru fiecare compilator.
Aceasta nseamn c diferite compilatoare vor avea diferite directive pragma.
Diversele forme pragma nu sunt definite de standardul
C++. Codul care depinde de pragma nu este portabil. n
mod normal este utilizat in procesul de debugging.
Pentru alte directive #pragma, verificai documentatia compilatoarelor i, de asemenea, standardul ISO/IEC C/C++ pentru orice actualizri.
40
7. MACROURI PREDEFINITE
__cplusplus , definit ca 1 dac este vorba de un modul C++ i este nedefinit n caz contrar
_LINE_, este un macro care contine o valoare intreaga,
care reprezinta numarul liniei din fisierul sursa supusa
compilarii.
_DATE_, este un macro care contine un sir de caractere ce
reprezinta data curenta a sistemului in forma: luna/zi/an
_FILE_, este un macro care contine un sir de caractere ce
reprezinta numele fisierului supus compilarii
_TIME_, este un macro care contine un sir de caractere ce
reprezinta timpul la care a inceput compilarea sub forma:
ore:minute:secunde 41
__STDC__ : are valoarea 1 dac compilatorul se
aliniaz standardului ANSI
Nu pot fi anulate cu directiva #undef Se pot utiliza n programe la fel ca orice ali
identificatori
Exemplu:
#include
#include
void main(void){
printf(Se compileaza %s, linia= %d, data= %s timpul= %s, _FILE_, _LINE_, _DATE_, _TIME_);
_getch();
}//main
42
OPERATORUL # - transform argumentul unei funcii macro ntr-un ir ntre ghilimele
#include
#define MAKESTR(str) #str
void main(void)
{
int valoare=100;
printf( %s is %d, MAKESTR(valoare), valoare);
}
Programul va afisa:
valoare is 100
43
OPERATORUL ## - concateneaz doi identificatori
#include
#define output(l) printf(%d %d\n,l##1, l##2)
void main(void){
int count1, count2;
int l1, l2;
count1=10;
count2=64;
l1=100;
l2=82;
output(count); //Afiseaza 10 si 64
output(l);//Afiseaza 100 si 82}
44
#include
#include
#define HELLO(x) printf("Hello, " #x "\n");
#define SHOWFUNC(x) Use ## Func ## x
int main(void)
{
// new concatenated identifier, UseFuncOne
char * SHOWFUNC(One);
// new concatenated identifier, UseFuncTwo
char * SHOWFUNC(Two);
SHOWFUNC(One) = "New name, UseFuncOne";
SHOWFUNC(Two) = "New name, UseFuncTwo";
HELLO(Birch);
printf("SHOWFUNC(One) -> %s \n",SHOWFUNC(One));
printf("SHOWFUNC(Two) -> %s \n",SHOWFUNC(Two));
_getch();
return 0;
}
45
46
8. ASERIUNI
Aceasta este o macrodefiniie folosit la gestiunea excepiilor dintr-un program C++.
Macrofuncia assert(), e definit n fiierul antet assert.h, i testeaz valoarea unei expresii date ca parametru.
Dac valoarea expresiei este 0 (false), atunci assert() afieaz un mesaj de eroare i apeleaz funcia abort() (din biblioteca stdlib.h) pentru a termina execuia programului.
Acest mecanism e util n procesul de debugging, de
exemplu pentru a testa dac o variabil are o valoare corect sau nu.
47
Ca exemplu, presupunem c variabila q nu poate avea niciodat o valoare mai mare dect 100 n program.
O aseriune poate fi folosit pentru a testa valoarea lui q i a afia un mesaj de eroare dac valoarea lui q e incorect.
Poate fi folosit urmtoarea construcie :
assert(q
EXEMPLU ASSERT #include
#include
#include
#include
#include
void TestString(char *string);
void main()
{
// first test array of char, 10 characters...
// should be OK for the 3 test conditions...
char test1[ ] = "abcdefghij";
// second test pointer to string, 9 characters...
// should be OK for the 3 test conditions...
char *test2 = "123456789";
// third test array char, empty...
// should fail on the 3rd condition, cannot be empty...
char test3[ ] = "";
49
printf("Testing the string #1 \"%s\"\n", test1);
TestString(test1);
printf("Testing the string #2 \"%s\"\n", test2);
TestString(test2);
printf("Testing the string #3 \"%s\"\n", test3);
TestString(test3);
_getch();
}//main
void TestString(char * string)
{
// set the test conditions...
// string must more than 8 characters...
assert(strlen(string) > 8);
// string cannot be NULL
assert(string != NULL);
// string cannot be empty....
// test3 should fail here and program abort...
assert(string != '\0');
} 50
51
9. FUNCII INLINE
inline val_ret nume_func(list_param_formali);
Sunt specifice limbajului C++
S-au introdus pentru a elimina neajunsurile
macrodefiniiilor cu parametri legate de verificrile de tip la apel
Se definesc ca i celelalte funcii, n plus se adaug cuvntul cheie inline
52
FUNCII INLINE
Funciile inline pstreaz proprietile funciilor legate de:
verificrile de la apel (numr i tip pentru parametri)
modul de transfer al parametrilor
domeniul declaraiilor locale i al parametrilor
i pentru aceste funcii are loc o substituie (inserare - expandare) de text, dar nu de ctre pp ci de ctre compilator
compilatorul poate s nu poat efectua o asemenea operaie, caz n care se genereaz o funcie obinuit
53
FUNCII INLINE
Restricii:
funcia trebuie s fie simpl (cteva instruciuni 2-3)
s nu conin instruciuni ciclice (do-while, for, while) nu obligatoriu
s fie definit i utilizat n acelai modul
nu pot fi compilate separat
nu se pot utiliza pointeri ctre aceste funcii
54
FUNCII INLINE
Exemple:
inline char comp(int a, int b)
{
if(ab) return('>');
return('=');
}
inline int max(int a, int b)
{
return ((a>b) ? a : b);
} 55
FUNCII INLINE
Comparaie ntre funcii inline i macrodefiniii cu parametri:
#define square(x) ((x)*(x))
cout
FUNCII INLINE
Funcia inline echivalent:
inline int square(int x)
{
return x*x;
}
In acest caz avem un apel obinuit de funcie:
cout
n cazul definirii unei funcii macro MAX:
#define MAX (l, j) ((l) > (j) ? (l ): (j))
putem apela macro-ul MAX astfel:
int a, b, c;
c = MAX (a*b, a+b); //care se va expanda in
//c = ((a*b) > (a+b) ? (a*b) : (a+b));
58
i n acest caz o funcie inline care ar realiza acelai lucru ar fi:
inline int mmax(int x, int y)
{
return (x) >(y) ? (x ): (y);
}
i apelul ei se face cu:
c = mmax(a*b, a+b);
astfel nct la compilare funcia mmax se va expanda ca i o funcie macro.
59