programare 5
TRANSCRIPT
-
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