+ All Categories

C++BOOK

Date post: 20-Nov-2015
Category:
Upload: iulian-best
View: 41 times
Download: 7 times
Share this document with a friend
Description:
C++BOOK
362
C A P I T O L U L I D E S C R I E R E A L I M B A J U L U I T U R B O C + + Turbo C++ este o implementare a limbajului conforma cu standardul ANSI elaborat de Comitetul Tehnic X3J11 intre iunie 1983 si decembrie 1988 cu unele extensii. De asemenea este oferita o implementare completa a limbajului C++ un superset orientat spre obiecte al limbajului C dezvoltat de Bjarne Stroustrup de la AT&T Bell Laboratories. Limbajul C++ adauga noi posibilitati de expresie limbajului C fata de care se indeparteaza pe alocuri; aceste diferente sint aratate in text. METALIMBAJUL FOLOSIT PENTRU DESCRIEREA SINTAXEI gramatica = regula... . regula = parte_stinga "=" parte_dreapta "." parte_stinga = neterminal parte_dreapta = alternativa [ "|" alternativa ]... . alternativa = [ element [ "..." ] ]... . element = element_de_baza | "[" alternativa "]" | "(" alternativa ")" . element_de_baza = neterminal | terminal . neterminal = identificator . terminal = delimitator caracter... delimitator . delimitator = "'" | '"' . Neterminalele au aspectul unor identificatori C. Terminalele sint siruri de caractere tiparibile inchise intre apostroafe (') sau ghilimele ("). Semnul egal (=) separa partea dreapta de partea stinga a unei reguli. Regulile sintactice se termina cu semnul punct (.). In cadrul partii drepte alternativele sint separate prin bare verticale (|). Parantezele drepte ([ si ]) o parte optionala. Parantezele rotunde sint folosite pentru grupare. Punctele de suspensie (...) arata ca elementul precedent se poate repeta de oricite ori. Exemplu: sir = ( ( element_a | element_b ) ";" )... . element_a = ( "A" | "a" ) [ "+" element_a ] . element_b = [ "(" element_b ")" "*" ]... ( "B" | "b" ) . Siruri generate de gramatica de mai sus: A + a ; B ; A + a + a ; ( ( b ) * ( B ) * ( b ) * B ) * ( b ) * b ; a + a + a + A ; a ; ((((B)*B)*(b)*b)*((B)*(B)*B)*b)*((B)*B)*b ; b ; (b)*b ; ( (b)*b ) * (b) * b ; 1
Transcript

Turbo C++

PAGE 297

C A P I T O L U L I

D E S C R I E R E A L I M B A J U L U I T U R B O C + +

Turbo C++ este o implementare a limbajului conforma cu standardul ANSI elaborat de Comitetul Tehnic X3J11 intre iunie 1983 si decembrie 1988 cu unele extensii. De asemenea este oferita o implementare completa a limbajului C++ un superset orientat spre obiecte al limbajului C dezvoltat de Bjarne Stroustrup de la AT&T Bell Laboratories. Limbajul C++ adauga noi posibilitati de expresie limbajului C fata de care se indeparteaza pe alocuri; aceste diferente sint aratate in text.

METALIMBAJUL FOLOSIT PENTRU DESCRIEREA SINTAXEI

gramatica = regula... .

regula = parte_stinga "=" parte_dreapta "."

parte_stinga = neterminal

parte_dreapta= alternativa [ "|" alternativa ]... .

alternativa = [ element [ "..." ] ]... .

element = element_de_baza |

"[" alternativa "]" |

"(" alternativa ")" .

element_de_baza = neterminal | terminal .

neterminal = identificator .

terminal = delimitator caracter... delimitator .

delimitator = "'" | '"' .

Neterminalele au aspectul unor identificatori C.

Terminalele sint siruri de caractere tiparibile inchise intre apostroafe (') sau ghilimele (").

Semnul egal (=) separa partea dreapta de partea stinga a unei reguli.

Regulile sintactice se termina cu semnul punct (.).

In cadrul partii drepte alternativele sint separate prin bare verticale (|).

Parantezele drepte ([ si ]) o parte optionala.

Parantezele rotunde sint folosite pentru grupare.

Punctele de suspensie (...) arata ca elementul precedent se poate repeta de oricite ori.

Exemplu:

sir = ( ( element_a | element_b ) ";" )... .

element_a = ( "A" | "a" ) [ "+" element_a ] .

element_b = [ "(" element_b ")" "*" ]... ( "B" | "b" ) .

Siruri generate de gramatica de mai sus:

A + a ; B ; A + a + a ; ( ( b ) * ( B ) * ( b ) * B ) * ( b ) * b ;

a + a + a + A ; a ; ((((B)*B)*(b)*b)*((B)*(B)*B)*b)*((B)*B)*b ;

b ; (b)*b ; ( (b)*b ) * (b) * b ;

STRUCTURA LEXICALA

Fazele traducerii unui program C

Text sursa in limbajul extins (fisier .C sau .CPP)

|

V

+-------------+

| Preprocesor |

+-------------+

|

V

Text sursa in limbajul de baza (invizibil pentru utilizator)

|

V

+------------+

| Compilator |

+------------+

| |

+------------------------+ |

| |

| V

| Text in limbaj de asamblare (.ASM)

| |

| V

| +----------+

| | Asamblor |

| +----------+

| |

+-------------------------->|

|

V

Text obiect (.OBJ)

|

V

+--------------------+

| Editor de legaturi |

+--------------------+

|

V

Program executabil (.EXE)

Spatii albe

Prin spatiu alb se inteleg sfirsitul unei linii sursa si caracterele spatiu (blanc, cod 20h), HT (control-I, cod 09h) si VT (control-K, cod 0Bh). Spatiile albe separa atomii lexicali dar nu au nici o alta semnificatie. Dintre caracterele care reprezinta spatii albe numai caracterul blanc poate sa apara intr-o constanta caracter sau sir de caractere; in acest caz el este tratat ca un caracter semnificativ.

Un caracter backslash ('\', cod 5Ch) urmat imediat de un terminator de linie sursa este ignorat impreuna cu terminatorul respectiv; in acest fel doua linii sursa fizice pot fi tratate ca o singura linie sursa logica. Aceasta proprietate a analizorului lexical este utila pentru scrierea unor macrodefinitii (vezi directiva #define a preprocesorului) care nu incap pe o singura linie si pentru construirea unor constante sir de caractere mai mari decit lungimea unei linii sursa; in acest din urma caz se prefera folosirea proprietatii analizorului sintactic de a concatena sirurile de caractere alaturate.

Comentarii

In limbajul C comentariile sint inchise intre /* si */; nu se admit comentarii imbricate. In C++ exista un al doilea fel de comentarii care incep cu // si se extind pina la sfirsitul liniei sursa. In faza de preprocesare fiecare comentariu este inlocuit cu un blanc.

Atomi lexicali

Exista 5 feluri de atomi lexicali: cuvinte cheie, identificatori, constante, siruri de caractere si separatori.

Cuvinte cheie

asmautobreakcasecatchcdeclchar class const continue_cs default delete do

double_dselse enum _es _export extern far float forfriend goto huge if

inline int interrupt _loadds long near newoperator pascal private protected public register _regparamreturn _saveregs _seg short signed sizeof _ssstatic struct switch template this typedef unionunsigned virtual void volatile while

Urmatoarele cuvinte cheie sint specifice limbajului C++:

catch class delete friend inline new operatorprivate protected private template this virtual

Urmatoarele cuvinte cheie nu sint recunoscute de standardul elaborat de ANSI, si sint specifice implementarii Turbo C++:

cdecl _cs _ds _es _export far huge interrupt _loadds near pascal _regparam _saveregs _seg _ss

Identificatori

Inlimbajul C, un identificator este format dintr-un numar oarecare de litere, cifre si liniute de subliniere, primul caracter fiind o litera sau o liniuta de subliniere. Literele mari nu sint echivalente cu cele mici, deci Sum, SUM si sum sint trei identificatori distincti. Pentru identificatorii globali importati din alte module se poate cere ca literele mari si mici sa fie considerate echivalente cu ajutorul optiunii /C a editorului de legaturi sau printr-o comanda din mediul integrat. Identificatorii declarati pascal sint intotdeauna convertiti la majuscule inaintea editarii legaturilor.

Numai primele 32 de caractere sint semnificative.

Constante

Constantele reprezinta valori fixe de tip intreg, real, enumerare sau caracter. Exista deci 4 feluri de constante: in virgula mobila, intregi, enumerare si caracter.

Constante intregi

Constantele intregi pot fi zecimale (sir de cifre zecimale din care prima nu este zero), octale (sir de cifre octale incepind cu cifra zero) sau hexazecimale (sir de cifre hexazecimale incepind cu 0x sau 0X). Intr-o constanta hexazecimala cifrele hexa A, ..., F pot fi reprezentate si prin a, ..., f.

In absenta unui sufix, tipul de date asociat unei constante intregi depinde de valoarea ei, astfel:

constante zecimale:

0 pina la 2**15 - 1 int

2**15 pina la 2**31 - 1 long

2**31 pina la 2**32 - 1 unsigned long

constante hexazecimale si octale:

0 pina la 2**15 - 1 int

2**15 pina la 2**16 - 1 unsigned

2**16 pina la 2**31 - 1 long

2**31 pina la 2**32 - 1 unsigned long

O constanta intreaga poate fi urmata de unul dinsufixele U, L sau UL, indicind respectiv tipul de date unsigned, long, unsigned long. In loc de literele mari U si L se pot folosi literele mici u si l.

Constante caracter

Constantele caracter pot avea doua forme: un caracter tiparibil diferit de backslas sau apostrof inchis intre apostroafe (de exemplu 'a'), sau o secventa escape inchisa intre apostroafe (de exemplu '\t'). Secventele escape recunoscute sint indicate mai jos.

Constantele caracter sint tratate ca valori cu sau fara semn in functie de starea optiunii de compilare -K (comanda Options/Compiler /Code/Unsigned_char a mediului integrat). Daca tipul caracter implicit este signed char, atunci constantele caracter sint tratate ca valori cu semn; daca tipul caracter implicit este unsigned char, ele sint tratate drept valori fara semn.

Compilatorul Turbo C++ accepta si constante caracter formate din doua caractere (de exemplu 'ab' sau '\r\n'). Acestea sint considerate valori intregi pe 16 biti si sint memorate cu primul caracter in octetul de pondere mica. O constanta caracter precedata de prefixul L este o constanta 'larga' de tip wchar_t (definit in stddef.h). Constantele 'largi' nu sint recunoscute inC++.

Secventa Cod Caracter

\a 07h BEL

\b 08h BS

\f 0Ch FF

\n 0Ah LF

\r 0Dh CR

\t 09h HT

\v 0Bh VT

\\ 5Ch \ (backslash)

\' 27h ' (apostrof)

\" 22h " (ghilimele)

\? 3Fh ? (semnul intrebarii)

\ooo ooo octal caracterul cu codul ooo (cel mult 3 cifre)

\xhh hh hexa caracterul cu codul hh (oricite cifre)

\Xhh hh hexa caracterul cu codul hh (oricite cifre)

Constante in virgula mobila

O constanta in virgula mobila cuprinde o parte intreaga, o parte fractionara, un exponent zecimal si eventual un sufix. Se poate omite partea intreaga sau partea fractionara dar nu amindoua. Se poate omite punctul zecimal sau exponentul dar nu amindoua. Exemple:

constanta valoare

23.45E6 23450000

.0 0

0. 0

1.23 1.23

2e5 200000

.9E-3 0.0009

In absenta oricarui sufix tipul de date al unei constante in virgula mobila este double. Sufixul F sau F forteaza tipul float iar sufixul l sau L tipul long double. Dimensiunile si domeniile de valori ale acestor tipuri sint date in urmatorul tabel:

tip dimensiune (biti) domeniu de valori

float 32 3.4e-38 pina la 3.4e38

double 64 1.7e-308 pina la 3.4e308

long double 80 1.1e-4932 pina la 1.1e4932

Constante de enumerare

Constantele de enumerare sint identificatori declarati odata cu definirea tipului de enumerare; valorile lor sint intregi si constantele de enumerare pot fi folosite acolo unde sint permise constante intregi.

Siruri de caractere

Un sir de caractere este format din zero sau mai multe caractere tiparibile diferite de ghilimele si backslash sau secvente escape inchise intre ghilimele: de exemplu "Numele \xE trandafirului \xF\n"

Tipul de date al unui sir de caractere este tablou de caractere iar clasa de memorare este static. Un sir de caractere este memorat ca un sir de octeti reprezentind caracterele din sir plus unoctet cu valoarea zero (caracterul NUL control-@) folosit ca terminator.Un sir vid (reprezentat in textul sursa prin"") este memorat ca un singur octet cu valoarea zero. Valoarea unui sir de caractere este un pointer catre primul caracter din sir.

Analizorul sintactic concateneaza sirurile de caractere adiacente (separate numai prin spatii albe). Aceasta caracteristica este adesea folosita pentru scrierea sirurilor lungi de caractere in locul concatenarii liniilor sursa cu backslash. Urmatoarele exemple sint echivalente:

printf ( "Acesta este un exemplu "

"de concatenare a sirurilor "

"de caractere\n" ) ;

printf ( "Acesta este un exemplu \

de concatenare a sirurilor \

de caractere\n" ) ;

Reprezentarea interna a constantelor

Standardul ANSI pentru limbajul C recunoaste ca domeniul de valori si spatiul de memorie necesar pentru reprezentarea tipurilor de baza depind de implementarea limbajului. InTurbo C++ sint valabile datele din tabelul de mai jos:

tip biti domeniu de valori reprezentare

unsigned char 8 0 .. 255 valoare absoluta

char 8 -128 .. 127 complement fata de 2

enum 16 -32768 .. 32767 complement fata de 2

short 16 -32768 .. 32767 complement fata de 2

int 16 -32768 .. 32767 complement fata de 2

unsigned 16 0 .. 65535 valoare absoluta

long 32 -2147483648 .. 2147483647 complement fata de 2

unsigned long 32 0 .. 4294967295 valoare absoluta

float 32 3.4e-38 .. 3.4e38 s 8e (1) 23m

double 64 1.7e-308 .. 1.7e308 s 11e (1) 52m

long double 80 1.1e-4932 .. 1.1e4932 s 15e 1 63m

near * 16 deplasament

far * 32 deplasament, baza

pentru tipurile in virgula mobila: s = semn; e = exponent binar polarizat; 1 = bit intreg al mantisei - implicit 1 la float si double, memorat la long double; m = mantisa.

Expresii constanteO expresie constanta este o expresie in care toti operanzii sint constante sau expresii constante. O expresie constanta se poate folosi oriunde este permisa o constanta. Urmatorii operatori sint interzisi in expresii constante: toti operatorii de atribuire, operatorii de incrementare si decrementare, apelul de functie si operatorul virgula.

Operatori

Prioritate Asociativitate

+----+-------------------------------------------------+--------+

| 1 | ( ) [ ] -> :: . | -----> |

+----+-------------------------------------------------+--------+

| 2 | ! ~ + - ++ -- & * | * | -----> |

+----+-------------------------------------------------+--------+

| 4 | * / % | -----> |

+----+-------------------------------------------------+--------+

| 5 | + - | -----> |

+----+-------------------------------------------------+--------+

| 6 | > | -----> |

+----+-------------------------------------------------+--------+

| 7 | < >= | -----> |

+----+-------------------------------------------------+--------+

| 8 | == != | -----> |

+----+-------------------------------------------------+--------+

| 9 | & | -----> |

+----+-------------------------------------------------+--------+

| 10 | ^ | -----> |

+----+-------------------------------------------------+--------+

| 11 | | | -----> |

+----+-------------------------------------------------+--------+

| 12 | && | -----> |

+----+-------------------------------------------------+--------+

| 13 | || | -----> |

+----+-------------------------------------------------+--------+

| 14 | ? : | * sint specifici limbajului C++.

In plus, C++ permite supraincarcarea operatorilor.

Scurta descriere a operatorilor

1. Operatori de apartenenta

( ... ) apel de functie

[ ... ] indexare

-> dereferentiere si selectia unui membru

. selectia unui membru

:: acces la un nume suspendat sau invizibil

2. Operatori unari

& adresa

* de referentiere

+ plus unar (identitate)

- minus unar (schimbarea semnului)

~ negare bit cu bit (complement fata de 1)

! negare logica (0 -> 1, diferit de zero -> 0)

(tip) conversie de tip

sizeof marimea spatiului de memorie necesar

new alocator

delete eliberarea memoriei alocate de new

3. Operatori pentru selectia membrilor unei clase

.* de referentiere a unui pointer la un membru

->* de referentiere urmata de de referentierea unui pointer la un membru.

4. Operatori multiplicativi

* inmultire

/ impartire

% restul impartirii intregi

5. Operatori aditivi

+ adunare

- scadere

6. Operatori de decalare bit cu bit

> decalare spre dreapta

7. Operatori relationali

< mai mic

mai mare

>= mai mare sau egal

8. Operatori de egalitate

== egal

!= diferit

Operatori de calcul logic bit cu bit

9. & produs logic bit cu bit

10. ^ suma modulo 2 bit cu bit

11. | suma logica bit cu bit

Operatori de calcul logic

12. && produs logic (operator in scurt-circuit)

13. || suma logica (operator in scurt-circuit)

14.Operator conditional

? ... : a ? b : c inseamna daca a atunci b altfel c

15.Operatori de atribuire

= atribuire

op= a op= b este o prescurtare de la a = a op b

16.Operator de secventiere

, evaluare secventiala de la stinga spre dreapta

Separatori

[ ... ] declararea dimensiunii unui tablou

( ... ) declararea unei functii; gruparea declaratorilor

{ ... } inceputul si sfirsitul unei structuri sau ale unui bloc

, separa elementele intr-o lista

; separa declaratiile si instructiunile

: separa eticheta de instructiune, declara un cimp de biti

... indica o lista variabila de parametri

* indica declararea unui pointer

& indica declararea unei referinte

= separa variabila declarata de lista de initializatori

~ indica un destructor

# indica o directiva; concateneaza atomii lexicali.

DECLARATII

Concepte referitoare la declaratii

Obiecte

Vom numi obiect o zona de memorie care poate fi folosita pentru pastrarea unei valori fixe sau variabile. Orice obiect are un nume folosit pentru a avea acces la zona de memorie respectiva si un tip de date care precizeaza dimensiunea zonei de memorie si modul in care trebuie interprtat continutul ei.Numele obiectului poate fi un simplu identificator insa in cazuri mai complicate se pot folosi expresii complexe pentru a referi obiectul in mod unic.

Prin declaratii se stabileste relatia dintre identificatori si obiectele denumite de acestia. Exista trei feluri de declaratii:

1) declaratii definitorii care stabilesc si crearea obiectului asociat:

2) declaratii de referire care au doar scopul de a informa compilatorul despre atributele obiectului si

3) tentative de definire care se comporta in mod normal ca o declaratie de referire dar pot juca si rolul unei declaratii definitorii daca in program nu apare nici o astfel de declaratie referitoare la acel obiect.

Declararea unui identificator precizeaza: tipul de date, clasa de memorare, domeniul de valabilitate, domeniul de vizibilitate, timpul de viata al obiectului asociat si atributele de legare.

Se numeste valoare stinga o expresie care desemneaza un obiect. O valoare stinga poate fi modificabila (este permisa schimbarea valorii obiectului) sau nemodificabila (nu este permisa schimbarea valorii obiectului asociat). De exemplu, fie declaratia:

int const *p ;

In acest caz atit p cit si *p sint valori stinga dar numai p este o valoare stinga modoficabila in timp ce *p este o valoare stinga nemodificabila.

Tipul de date si clasa de memorare

Tipul unui obiect precizeaza multimea valorilor pe care acest obiect le poate avea; aceasta multime poate depinde de implementare.Tipul obiectului dicteaza dimensiunea zonei de memorie asociate obiectului; aceasta dimensiune poate fi aflata cu ajutorul operatorului sizeof.

Clasa de memorare indica locul in care se aloca spatiu pentru obiectul respectiv. Obiectele care au clasa de memorare externsau static se aloca insegmente de date (alocare statica); clasa de memorare auto indica alocarea de spatiu pe stiva (pentru obiectele locale definite incadrul unei functii sau al unui bloc); clasa de memorare register are aceeasi semnificatie ca si auto avind in plus valoarea unei indicatii adresate compilatorului sa incerce sa-i aloce respectivului obiect un registru al procesorului. Se pot crea obiecte dinamice in timpul executiei programului cu ajutorul functiilor din familia malloc sau (inC++) cu ajutorul operatorului new; pentru aceste obiecte se aloca spatiu intr-o zona special destinata alocarii dinamice, zona numita heap.

Domeniul de valabilitate

Domeniul de valabilitate al unui identificator este acea portiune a programului sursa in care este valabila legatura dintre identificator si obiectul asociat. Exista urmatoarele feluri de domenii de vizibilitate:

bloc incepe cu locul declaratiei obiectului si se extinde pina la sfirsitul blocului in care apare declaratia; parametri

formali ai functiilor au valabilitate incadrul blocului care defineste functia.

functie singurii identificatori care sint valabili intot blocul care defineste o functie sint etichetele; ele pot fi

referite oriunde in corpul functiei chiar inainte de punctul de definire si chiar in afara blocului in care

sint definite.

prototip parametrii formali declarati in cadrul unui prototip de functie sint valabili numai incadrul prototipului (a nude se confunda declaratia unei functii cu definirea ei -- in acel caz parametrii formali sint valabili in tot blocul functiecare defineste functia).

fisier identificatorii declarati pe nivelul superficial in afara oricarei functii sint valabili in tot textul din fisierul

sursa respectiv incepind cu punctul in care apare declaratia lor si pina la sfirsitul fisierului.

clasa domeniu de valabilitate specific limbajului C++. Este domeniul de valabilitate al membrilor unei clase.

Spatii de nume

etichete trebuie sa fie unice in cadrul unei functii

nume de structuri, trebuie sa fie unice in cadrul blocului in care sint declarate;

clase, uniuni si cele declarate pe nivelul superficial trebuie sa fie unice printre numele

enumeraride structuri, uniuni, clase si enumerari declarate pe nivelul superficial.

nume de membri de trebuie sa fie unice in cadrul structurii, clasei sau uniunii respective;

structuri, uniuni nu sint restrictii asupra numelor membrilor a doua

sau clase structuri, uniuni sau clase diferite.

nume de variabile, trebuie sa fie unice printre numele de variabile,

tipuri si constantetipuri si constante de enumerare din domeniul lor de valabilitate

de enumerare

(aparitia unui nume identic suspenda semnficatia anterioara).

Domeniul de vizibilitate

Domeniul de vizibilitate al unui identificator este acea parte a domeniului de valabilitate in care identificatorul poate fi folosit pentru a avea acces la obiectul asociat. Domeniul de vizibilitate al unui identificator este acea parte din domeniul sau de valabilitate in care semnificatia sa originala nu este suspendata de o noua declaratie.

valabilitatea lui int i vizibilitate

{

int i ; * *

... * *

{ * *

double i ; *

... *

} * *

... * *

}

Timpul de viata

Timpul de viata se refera la perioada de timp in decursul careia obiectele asociate identificatorilor au zone de memorie alocate.

Exista trei feluri de timpuri de viata:

static obiectelor statice li se aloca memorie la inceputul executiei programului si pastreaza acel spatiu pina la

sfirsitul executiei. Toate obiectele care au valabilitate in cadrul unui fisier au timp de viata static; celelalte

obiecte pot avea timp de viata static daca sint declarate cu clasa de memorare static sau extern.

automatic obiectelor automatice li se aloca memorie inmomentul in care controlul patrunde in blocul sau functia in

care ele sint definite; zona de memorie este eliberata inmomentul in care controlul paraseste acel bloc sau

functie. Obiectele automatice au intotdeauna valabilitate incadrul unui bloc; dintre obiectele cu valabilitate in cadrul unui bloc numai cele declarate cu clasa de memorare auto (implicita) sau register au timp de viata automatic.

dinamic obiectele dinamice sint create si distruseexplicit de program prin apeluri catre functiile din familia malloc /

free (sau, in C++, folosind operatorii new si delete).

Atribute de legare

Prin unitate de compilare se intelege un fisier sursa plus textul din fisierele incluse (cu directiva #include) dar fara textul omis datorita directivelor de compilare conditionata (#if... #else #endif). Unitatea de compilare este textul transmis de preprocesor compilatorului propriu-zis. UnprograMexecutabil este de obicei format din module obiect provenind dincompilarea mai multor unitati de compilare. Pentru asocierea corecta a identificatorilor cu

obiectele referite fiecare atribut poate avea unul din trei atribute de legare: legare externa, legare interna, fara legare.

Un identificator cu legare externa este asociat cu un singur obiect in intregul program executabil indiferent in cite unitati de compilare este declarat. Un identificator cu legare interna este asociat cu cite un obiect diferit pentru fiecare unitate de compilare in care e declarat indiferent de cite ori este declarat in unitatea respectiva. Un identificator fara legare reprezinta un obiect unic pentru fiecare declaratie in care apare.

Domeniu de valabilitateClasa de memorare Atribute de legare

fisier extern (implicit) legare externa

fisier static

legare interna

Un identificator care este declarat atit extern citsi static va avea legare interna in Cdar legare externa in C++.

bloc auto (implicit)

fara legare

bloc extern

acelasi atribut de legare cu cel asociat unei declaratii vizibile

a identificatorului cu valabilitate in intregul fisier. Daca nu exista

oastfeldedeclaratie atunci se ia legare externa.

bloc static

ca mai sus; prin lipsa legare interna.

O functie declarata fara o clasa de memorare explicita are legare externa. Un identificator care nu reprezinta o variabila sau o functie (de exemplu un typedef) este considerat fara legare.

Sintaxa declaratiilor

unitate_de_compilare = declaratie_externa... .

declaratie_externa = definitie_de_functie | declaratie .

declaratie = [specificatori_decl] [lista_declaratori] ";" |

declaratie_asm |

declaratie_de_functie |

declaratie_de_legare . C++

Partea de specificare a tipului si a clasei de memorare

specificatori_decl = specificator_declarativ... .

specificator_declarativ = clasa_de_memorare |

tip |

specificator_fct |

"friend" | C++

"typedef" .

clasa_de_memorare = "auto" | "register" | "static" | "extern" .

specificator_fct = "inline" | "virtual" .

tip = nume_de_tip |

specificare_de_clasa |

specificare_enum |

specificare_tip_elaborat |

"const" |

"volatile" .

nume_de_tip = nume_de_clasa |

nume_typedef |

"char" | "short" | "int" | "long" | "signed" |

"unsigned" | "float" | "double" | "void" .

specificare_tip_elaborat =

cheie_de_clasa ( identificator | nume_de_clasa ) |

"enum" nume_enum .

cheie_de_clasa = "struct" |

"union" |

"class" . C++

specificare_enum = "enum" [identificator] "{" lista_enum "}" .

lista_enum = element_enum [ "," element_enum ]... .

element_enum = identificator [ "=" expresie_constanta ] .

specificare_de_clasa = antet_clasa "{" [lista_membri] "}" .

antet_clasa = cheie_de_clasa [identificator] [specificare_baza] |

cheie_de_clasa nume_de_clasa [specificare_baza] .

specificare_baza = ":" lista_baza .

lista_baza = specificator_baza ["," specificator_baza]... .

specificator_baza = nume_de_clasa |

"virtual" [specificator_acces] nume_de_clasa |

[specificator_acces] "virtual" nume_de_clasa .

specificator_acces = "private" | "protected" | "public" .

lista_membri = declaratie_membru... |

specificator_acces ":" [lista_membri] .

declaratie_membru = [specificatori_decl] [declaratori_membri] ";" |

definitie_de_functie [ ";" ] | C++

nume_calificat ";" . C++

declaratori_membri = declarator_membru ["," declarator_membru]... .

declarator_membru = declarator [specificator_pur] |

[identificator] ":" expresie_constanta .

specificator_pur = "=" "0" .

Lista de declaratori

lista_declaratori = declarator_init ["," declarator_init]... .

declarator_init = declarator [initializator] .

declarator = nume_declarat |

lista_modificatori |

operator_ptr declarator |

declarator "(" decl_parametri ")" lista_cv | C++

declarator "(" decl_parametri ")" |

declarator "[" [expresie_constanta] "]" |

"(" declarator ")" .

nume_declarat = nume |

["~"] nume_de_clasa | C++

nume_typedef .

lista_modificatori = modificator... .

modificator = "cdecl" | "pascal" | "interrupt" |

"near" | "far" | "huge" .

operator_ptr = "*" [lista_cv] |

"&" [lista_cv] | C++

nume_de_clasa "::" "*" [lista_cv] . C++

lista_cv = calificator_cv... .

calificator_cv = "const" | "volatile" .

decl_parametri = [lista_decl_parametri] |

lista_decl_parametri "," "..." |

lista_decl_parametri "..." . C++

lista_decl_parametri = decl_parametru ["," decl_parametru]... .

decl_parametru =

specificatori_decl declarator |

specificatori_decl declarator "=" expresie | C++

specificatori_decl [declarator_abstract] |

specificatori_decl [declarator_abstract] "=" expresie . C++

declarator_abstract =

operator_ptr [declarator_abstract] |

[declarator_abstract] "(" decl_parametri ")" [lista_cv] |

[declarator_abstract] "[" [expresie_constanta] "]" |

"(" declarator_abstract ")" .

initializator = "=" expresie |

"=" "{" lista_initializatori "}" |

"(" lista_expresii ")" . C++

lista_initializatori = expresie ["," expresie]... |

"{" lista_initializatori [ "," ] "}" .

Definitii de functii

nume_de_functie = identificator |

nume_functie_conversie | C++

nume_functie_operator . C++

nume_functie_conversie =

"operator" specificatori_de_tip [operator_ptr] .

nume_functie_operator = "operator" operator .

definitie_de_functie =

[specificatori_declarativi] declarator [ctor_init] bloc.

ctor_init = ":" lista_initializatori_mem . C++

lista_initializatori_mem = init_mem ["," init_mem]... .

init_mem = nume_clasa "(" lista_parametri ")" |

identificator "(" lista_parametri ")" .

declaratie_de_legare =

"extern" sir_de_caractere "{" [lista_declaratii] "}" |

"extern" sir_de_caractere declaratie .

lista_declaratii = declaratie [";" declaratie]... .

Tipuri de date

Specificatorul de tip, impreuna cu unul sau mai multi modificatori optionali, este folosit pentru precizarea tipului oricarui identificator declarat. Prin traditie specificatorul de tip int poate fi omis deoarece el reprezinta optiunea implicita. Deoarece in C++ aceasta ar putea duce la ambiguitati practica programarii in C++ cere ca toti specificatorii de tip int sa fie precizati explicit.

Exista patru categorii de tipuri de date: void, scalar, functie si agregat. Tipurile scalare sint tipuri aritmetice, de enumerare, pointer si (in C++) referinta. Tipurile agregate sint tablou, structura, uniune si (in C++) clasa.

Tipuri fundamentale

void

Tipul void este un tip care nu contine nici o valoare. Este folosit in urmatoarele situatii:

a) declararea unei liste vide de parametri formali:

int func (void) ; // func nu are parametri

b) declararea unei functii care nu intoarce nici o valoare:

void func (int n) ; // func nu intoarce nici o valoare

c) declararea unui pointer generic (unpointer care poate contine adresa oricarui fel de obiect):

void *ptr ; // ptr este un pointer generic

d) in expresii de conversie:

(void) errfunc () ; // errfunc apelata ca o procedura

Tipurile aritmetice

Tipurile aritmetice sint tipuri intregi si in virgula mobila; ele se construiesc cu ajutorul urmatoarelor cuvinte cheie:

char int float doublesigned unsigned long short

Tipuri intregi Sinonim

-------------- ----------------

char

unsigned char char (in prezenta unei optiunii -K)

signed char char (implicit, in absenta optiunii -K)

short int int

signed short int int

unsigned short int unsigned

int

signed int int

unsigned

unsigned int unsigned

long

long int long

signed long int long

unsigned long

unsigned long int unsigned long

Tipuri in virgula mobila

float

double

long double

Conversii aritmetice

Daca operanzii unui operator aritmetic binar nu sint de acelasi tip atunci au loc urmatoarele conversii standard:

- char, unsigned char sau signed char ---> int

- short, signed short ---> int

- unsigned short ---> unsigned

- apoi, daca operanzii tot nu au acelasi tip, tipul mai slab se converste la tipul mai tare.In aceasta situatie particulara se foloseste urmatoarea ierarhie de tipuri:

long double

double

float

unsigned long

long

unsigned

int

- tipul rezultatului este tipul comun la care au ajuns operanzii.

La atribuire, conversia unei valori de tip intreg mai scurt catre un tip mai lung se face prin umplerea cu zero a bitilor mai semnificativi sau cu extinderea semnului, dupa cum tipul valorii care trebuie convertita este fara semn sau cu semn. Conversia unei valori mai lungi catre untip mai scurt se face prin neglijarea bitilor mai semnificativi.

Initializarea variabilelorIn lipsa unei initializari explicite obiectele cu timp de viata static sint automat initializate cu zero daca sint de tip aritmetic respectiv cu NULL daca sint pointeri.

Initializatorii expliciti se plaseaza dupa declaratorul la care se refera separati de acesta prin semnul egal. Daca obiectul initializat este unagregat pentru initializare se foloseste o lista de expresii inchisa inacolade (cite o expresie pentru fiecare componenta; daca o componenta este la rindul ei un agregat ei ii corespunde o lista de expresii inacolade etc.). Trebuie respectate urmatoarele reguli:

1) numarul de initializatori nu poate fi mai mare decit numarul de componente de initializat.

2) nu se pot initializa decit obiecte sau tablouri cu dimensiune nedefinata.

3) expresiile folosite pentru initializare trebuie sa fie constante in urmatoarele situatii: - la initializarea unui obiect cu timp de viata static (nu este ceruta aceasta conditie in C++);

- la initializarea unui tablou, unei structuri sau unei uniuni.

4) nu se pot initializa identificatori cu valabilitate ininteriorul unui bloc, dar cu legare externa sau interna.

5) daca intr-o lista inchisa in acolade are mai putine elemente decit componente are agregatul initializat, restul componentelor se vor initializa automat cum s-a aratat mai sus.

Obiectele de tip scalar se initializeaza folosind o singura expresie care poate fi eventual inchisa in acolade. Uniunile se initializeaza cu o singura expresie corespunzind ca tip primului membru al uniunii. Structurile si uniunile se pot initializa cu o expresie de tip structura sau uniune corespunzatoare; valoarea initiala a structurii sau uniunii va fi valoarea obiectului citat.

Tablourile de caractere se pot initializa cu siruri de caractere; tablourile de caractere 'largi' (de tip wchar_t) se pot initializa cu siruri 'largi' de caractere.

Exemple:

int days [7] = { 1, 1, 1, 1, 1, 1, 1 } ;

char name1 [] = { "Unknown" } ;

char name2 [] = "Unknown" ;

struct mystruct

{

int i ;

char str [21] ;

double d ;

} myvar = { 20, "Borland", 3.1416 } ;

Prezenta unui initializator intr-o declaratie facuta pe nivelul superficial indica o declaratie definitorie; pentru acelasi obiect nupotexista doua declaratii definitorii intr-un program executabil. Un obiect automatic poate fi initializat cu o expresie de tip compatibil la atribuire cu obiectul. Obiectele statice trebuie initializate cu expresii constante (in C++regula e relaxata: pot fi orice expresii continind numai constante si variabile definite anterior).

Clase de memorare

auto se poate folosi numai pentru identificatori cu valabilitate in cadrul unui bloc; implica timp de viata

automatic si fara legare. Fiind clasa de memorare implicita pentru identificatorii cu valabilitate incadrul

unui bloc, este rareori precizata explicit.

register se poate folosi numai pentru variabile locale si pentru parametrii formali ai functiilor; are acelasi sens ca

auto dar solicita compilatorului sa aloce variabilei unregistru al procesorului daca acest lucru este posibil

(daca nu este posibil nu se intimpla nimic).

extern implica legare externa si timp de viata static; este clasa de memorare implicita pentru identificatorii cu

valabilitate in cadrul unui fisier sursa.

static indica legare interna si timp de viata static. In C++ unmembru static al unei clase are aceeasi valoare in toate

instantierile clasei respective; o functie membru al unei clase declarata static poate fi folosita independent de o

instantiere particulara a clasei respective.

Cuvintul cheie typedef se foloseste sintactic ca si cum ar fi o clasa de memorare; rolul sau este de a da un nou nume unui tip de date, pentru simplificarea declaratiilor ulterioare, ca in exemplul:

typedef double * (* PFD) (void) ;

PFD pointer_to_function [10] ;

Modificatoriconst

Interzice modificarea obiectului declarat fie prin atribuire fie prin efecte laterale (incrementare, decrementare etc.).

const double pi = 3.14159 ;

char * const s1 = "Hello, world!" ; // s1 e un pointer constant

char const * s2 = "Bonjour, monde!" ; // *s2 este un sir constant

s1 = "Guten tag!" ; // ilegal, s1 nu e modificabil

s2 = s1 ; // corect, s2 poate fi modificat

strcpy ( s1, "Guten tag!" ) ; // corect, *s1 e modificabil

strcpy ( s2, s1 ) ; // ilegal, *s2 nu e modificabil

InC++ const are de asemenea efectul ascunderii obiectului declarat si interzice legarea externa (trebuie folosit extern const). Un pointer catre un obiect const nu poate fi atribuit unui pointer catre un obiect non-const.

volatile

Un obiect declarat volatile poate fi modificat in orice moment nu numai de program ci si de forte din afara programului (intreruperi s.a.). Efectul modificatorului volatile este de a interzice compilatorului efectuarea unor optimizari in privinta acestor variabile (alocarea de registre, optimizari de bucle, etc.).

In C++ modificatorii const si volatile pot fi aplicati si claselor si functiilor membre ale unei clase.

Numai modificatorii const si volatile sint recunoscuti de standardul ANSI; urmatorii modificatori sint specifici implementarii Turbo C++.

interrupt

Se poate aplica numai functiilor; are ca efect generarea de cod pentru salvarea/restaurarea registrelor AX, BX, CX, DX, SI, DI, ES si DS (BP, SP, SS, CS si IP sint salvate/restaurate in mod normal de orice functie C). Revenirea din functie se va face cu o instructiune IRET. Functiile interrupt poat fi folosite fara pericol ca rutine de tratare a unor intreruperi, generate prin hardware sau software.

Functiile interrupt este bine sa fie declarate de tip void. Pentru alte modele de memorie decit huge la intrarea in functie DS contine baza segmentului de date al programului. Pentru modelul de memorie huge, DS contine baza segmentului de date al modulului.

cdecl si pascal

Afecteaza tratarea identificatorilor cu legare externa si modul de transmitere al parametrilor catre functiile apelate.

cdecl pascal

--------------------------------------------------------------------

identificatorii cu legare externa identificatorii cu legare externa

sint trecuti in fisierul sint trecuti in fisierul

obiect cu litere mici si obiect convertiti la majus-

mari asa cum apar in cule fara a li se adauga

fisierul sursa cu o liniuta vreo liniuta de subliniere.

de subliniere adaugata ca

prim caracter

la apel parametrii sint plasati la apel parametrii sint plasati

in stiva de la dreapta la in stiva de la stinga la

stinga dreapta

functia apelanta este cea care functia apelata are datoria sa

elimina parametrii dinstiva elimine parametrii din stiva

Functia main (programul principal) trebuie neaparat sa fie compilata cu modificatorul cdecl (implicit sau explicit).

In lipsa oricarei precizari modificatorul considerat implicit este cdecl. Optiunea pascal poate deveni implicita in prezenta optiunii de compilare -p (sau a comenzii corespunzatoare din mediul integrat)

Modificatorii specifici pentru pointeri

Modificatorii specifici pentru pointeri sint near, far, huge, _cs, _ds, _ss, _es, _seg (vezi mai jos).

Modificarea tipului functiilor

Orice functie care nu este declarata interrupt poate fi declarata cu unul din modificatorii near, far, huge; precizarea explicita a acestor modificatori are ca efect ignorarea modelului de memorie stabilit pentru unitatea de compilare. (Vezi mai jos o discutie despre modelele de memorie).

model de memorie modificator implicit pentru functii

tiny, small, compact near

medium, large far

huge huge

modificator ce fel de CALL ce fel de RET DS la intrarea in functie

near near near nemodificat

far far far nemodificat

huge far far seg. de date

al modulului

Modificatori speciali pentru functii

_export nici un efect (acceptat de analizorul sintactic pentru a asigura compatibilitatea cu compilatorul de sub OS/2).

_loadds are ca efect incarcarea registrului DS la intrarea in functie la fel ca in prezenta modificatorului huge dar

nu implica nici near, nici far nici huge.

_saveregs cere generarea de cod pentru pastrarea tuturor registrelor (eventual cu exceptia lui AX, DX etc. folosite pentru valoarea intoarsa de functie).

Recapitulare privind construirea tipurilor de date

Fie TIP un tip de date anterior definit. Pentru fiecare din declaratiile urmatoare vom preciza tipul de date asociat identificatorului declarat.

TIP id1 ; TIP

TIP *id2 ; pointer catre TIP

TIP id3 [] ; tablou (deschis) de elemente TIP

TIP id4 [10] ; tablou de 10 elemente TIP

TIP *id5 [] ; tablou de pointeri catre TIP

TIP *(id6 []) ; acelasi lucru

TIP (*id7) [] ; pointer la un tablou de elemente TIP

TIP &id8 ; referinta la un obiect TIP (numai in C++)

TIP id9 () ; functie care intoarce o valoare TIP

TIP *idA () ; functie care intoarce un pointer catre TIP

TIP *(idB ()) ; acelasi lucru

TIP (*idC) () ; pointer la o functie care intoarce TIP

Pointeri

Un pointer este o variabila care are ca valoare adresa unei zone de memorie. Sint doua categorii de pointeri: pointeri catre variabile si pointeri catre functii. Desi valorile pointerilor sint numere care au multe dintre proprietatile numerelor intregi totusi pointerii au propriile lor reguli in ceea ce priveste atribuirile, conversiile si efectuarea operatiilor aritmetice. Dimensiunea unui pointer depinde de modelul de memorie folosit (vezi mai jos) si eventual de modificatorii folositi la declararea pointerului.

Pointeri catre functii

Un pointer catre o functie are ca valoare adresa (de obicei intr-un segment decod) de la care incepe codulexecutabil al functiei.

Exista o diferenta semnificativa intre limbajele C si C++in ceea ce priveste tipul de date al unui pointer catre o functie: in C acesta este 'pointer catre o functie care intoarce o valoare de un anume tip' pe cind in C++ este 'pointer catre o functie care are urmatorii parametrii si intoarce o valoare de un anume tip'. De exemplu, declaratia

int (*func) () ;

declara in C un pointer catre o functie care intoarce un rezultat intreg, pe cind inC++ declara un pointer catre o functie care NU ARE PARAMETRI si intoarce un rezultat intreg. Ca un exemplu suplimentar,

int (*func2) (int, long) ;

declara in C++ un pointer catre o functie care are un parametru intreg si unul long si care intoarce un rezultat intreg.

Declararea pointerilor

Orice pointer trebuie declarat ca fiind unpointer catre obiecte sau functii de un anume tip, chiar daca acel tip este void.

Oricarui pointer i se poate atribui ca valoare constanta intreaga 0 (definita in fisierele antet standard cu mnemonica NULL) garantindu-se ca aceasta valoare este diferita de orice valoare valida a unui pointer.Daca p1 si p2 sint pointeri catre tipurile t1 si respectiv t2 atunci o atribuire a valorii lui t2 catre t1 nu este permisa decit daca t1 si t2 sint acelasi tip sau t1 este void sau se foloseste o conversie explicita. In C atribuirea este permisa fara o conversie explicita si daca t2 este void.

Exista restrictii privitoare la atribuirile efectuate intre pointeri de diferite dimensiuni (pointeri near pe 16 biti si pointeri far sau huge pe 32 de biti). Este permisa atribuirea unui pointer mai scurt catre unul mai lung dar atribuirea inversa este permisa numai cu o conversie explicita.

Pointerii si modificatorul const

int i ;

int * p ;

int *const cp = &i ;

const int c = 7 ;

const int * pc ;

const int *const cpc ;

i = c ; // permis: non-const = const

*cp = c ; // permis: non-const = const

++pc ; // permis: incementeaza un obiect non-const

pc = cpc ; // permis: non-const = const

c = 0 ; // ilegal: modifica un obiect const

c-- ; // ilegal din acelasi motiv

*pc = 3 ; // interzis: *pc este const

cp = &c ; // interzis: cp este const

cpc++ ; // interzis: cpc este const

p = pc ; // interzis: *p este non-const si ar putea fi posibila

// modificarea lui *pc prin intermediul lui p

Reguli similare se aplica si pentru modificatorul volatile.Atentie const si volatile se pot aplica impreuna unui identificator.

Operatii aritmetice cu pointeri

Operatiile aritmetice permise sint: adunarea unui pointer cu un intreg, scaderea unui intreg dintr-un pointer, scaderea a doi pointeri, compararea unui pointer cu constanta NULL (valoarea intreaga 0) si compararea a doi pointeri. Singura operatie aritmetica permisa asupra pointerilor catre functii este compararea cu constanta NULL.

Adunarea unui pointer cu un intreg

Rezultatul este un pointer de acelasi tip.Pointerul trebuie sa aiba ca valoare adresa unui element de tablou; rezultatul adunarii este adresa elementului al carui indice este egal cu suma dintre indicele elementului catre care indica pointerul plus valoarea intregului.

Din motive legate de modul de generare a adreselor fizice de catre procesor rezultatul nu este valid decit daca indicele rezultat din calcul este mai mare sau egal cu zero si mai mic sau egal cu numarul de elemente din tablou.

Scaderea unui intreg dintr-un pointer

Se face ca si cum s-ar aduna la pointer valoarea intreaga respectiva cu semn schimbat.

Scaderea a doi pointeri

Cei doi pointeri trebuie sa indice catre doua elemente din acelasi tablou; rezultatul este unintreg egal cu diferenta indicilor celor doua elemente.

Compararea a doi pointeri

Cei doi pointeri trebuie sa indice catre doua elemente din acelasi tablou; rezultatul comparatiei este egal cu rezultatul comparatiei indicilor celor doua elemente de tablou.

Valorile apartinind unui tip pointer pot fi convertite catre orice alt tip pointer prin folosirea unei conversii explicite.

C++ introduce tipurile referinta care vor fi prezentate in sectiunea dedicata trasaturilor specifice limbajului C++.

Tablouri

Declaratia

TIP declarator "[" [expresie_constanta] "]" ";"

introduce un tablou compus dinelemente de tipul TIP. Tablourile multidimensionale sint considerate tablouri de tablouri ca in exemplul

int m [5] [7] ;

care declara un tablou m cu elemente, fiecare fiind un tablou cu elemente intregi.

In anumite contexte se poate omite constanta care precizeaza cite elemente are tabloul (pentru tablouri multidimensionale numai constanta corespunzatoare primei dimensiuni poate fi omisa). Astfel de tablouri se numesc tablouri deschise; tablourile deschise sint permise acolo unde nu este necesara cunoasterea informatiei referitoare la marimea tabloului pentru rezervarea de memorie; cele mai uzuale situatii de acest fel sint cele in care tabloul este declarat extern si deci spatiul de memorie este alocat in alta parte si atunci cind tabloul este un parametru formal al unei functii.

CA O EXTENSIE A STANDARDULUI ANSI Turbo C++ permite declararea unui tablou deschis ca ultim membru al unei structuri; o structura de acest fel este de obicei folosita incontextul alocarii dinamice a memoriei; tabloul deschis adaugat ca ultim membru nu creste marimea structurii cu eventuala exceptie a unui octet adaugat pentru a asigura alinierea tabloului la adresa para (numai in unele situatii si numai daca utilizatorul a precizat aceasta optiune).

Cu exceptia cazurilor incare este vorba de argumentul lui sizeof sau de operandul lui (luarea adresei) o expresie a carui tip este 'tablou de ...' este automat convertita la un pointer catre primul element al tabloului; acest pointer este o constanta deci nu este o parte stinga.

Functii

In C functia este singurul fel de (sub)program jucind atit rolul functiilor cit si al procedurilor (subrutinelor) din alte limbaje de programare.

Orice program executabil trebuie sa contina o functie numita main care joaca rolul de program principal fiind apelata de siste la inceputul executiei programului.

Clasa de memorare implicita pentru functii este extern indiferent de locul in care apare declaratia sau definitia functiei. Pentru a modifica atributul de legare asociat numelui functiei din 'legare externa' in 'legare interna' se poate utiliza explicit clasa de memorare static in definitia (si declaratiile) functiei.

Declaratii si definitii de functii

Functiile sint de obicei declarate ca prototipuri infisierele antet (#include) ale sistemului sau ale utilizatorului.O functie poate fi declarata de oricite ori, cu conditia ca declaratiile sa fie compatibile. Cu exceptia functiilor supraincarcate dinC++ pentru fiecare functie este permisa o singura definitie (o definitie se deosebeste de o declaratie prin aceea ca contine o instructiune compusa -- numita corpul functiei -- care descrie prelucrarea efectuata de functie). Evident aceasta definitie trebuie sa fie compatibila cu eventualele declaratii precedente. Daca inC declararea functiilor inainte de utilizarea lor nu este neaparat necesara in C++este obligatorie.

In limbajul dezvoltat initial de Kernighan si Ritchie o functie era declarata implicit prinutilizarea ei intr-un apel de functie sau putea fi explicit declarata astfel:

[tip] nume_functie "(" ")"

Daca nu se precizeaza tipul functiei se lua implicit tipul int; o functie poate intoarce orice fel de valoare mai putin un tablou sau o functie. Pentru a putea ingadui compilatorului sa faca verificarile uzuale privind numarul si tipul parametrilor ANSI a introdus o noua forma de declaratie pentru functii numita prototip:

[tip] nume_functie "(" lista_declaratori_parametri ")" ";"

Declaratorii din lista precizeaza tipul fiecarui parametru permitind compilatorului sa faca verificarile necesare:

long lmax ( long v1, long v2 ) ; // prototipul lui lmax

main ()

{

int limit = 32 ;

char ch = 'A' ;

long mval ;

mval = lmax (limit, ch) ; // conversii automate

}

In apelul lui lmax compilatorul genereaza automat secvente de conversie pentru parametri, ca si cum apelul ar fi fost scris

mval = lmax ( (long) limit, (long) ch ) ;

eliminindu-se astfel o mare sansa de eroare. Prototipurile de functii au deasemenea un mare rol inscrierea programelor autodocumentate imbunatatind claritatea textului sursa. O functie care nu are parametri se declara folosind cuvintul void in locul listei de parametri:

[tip] nume_functie "(" "void" ")"

In C++ acelasi inteles il are omiterea listei de parametri. Mai jos se dau o serie de exemple recapitulative privind declararea functiilor:

int f () ; // in C, o functie care intoarce un intreg si despre parametrii careia nu se stie nimic

int f () ; // in C++, o functie fara parametri care intoarce un intreg

int f (void) ; // o functie intreaga fara parametri

int p (int, long) ; // o functie intreaga cu 2 parametri: un intreg si un long

int pascal (void) ; // o functie intreaga fara paramatri care respecta secventa de apel pascal

char far *s (char *source, int kind) ; // o functie care intoarce un pointer pe 32 de

// biti catre char avind 2 parametri: un pointer catre char (lungimea sa depinde de modeul de

// memorie implicit) si un intreg

int printf (char *format, ...) ; // o functie intreaga cu cel putin un parametru, care este un pointer catre char

int (*fp) (int) ; // un pointer catre o functie intreaga cu un parametru intreg

Sintaxa unei definitii de functie este:

definitie_de_functie =

[specificatori_declarativi] declarator

[lista_declaratii]

bloc

In general, definitia unei functii consta din:

1) Clasa de memorare extern sau static (implicit extern).

2) Tipul valorii intoarse de functie eventual void.Prin lipsa se ia tipul int. Elementele 1) si 2) se pot amesteca.

3) O lista optionala de modificatori: cdecl, pascal, near, far,huge, interrupt, _saveregs, _loadds. Alegerile implicite depind de modelul de memorie folosit si de optiunile de compilare.

4) Numele functiei.

5) Lista de declaratori pentru parametrii formali inchisa in paranteze; lista poate fi vida.Metoda preferata de a indica o functie fara parametri este scrierea cuvintului void in locul listei de parametri.

6) Corpul functiei, sub forma unei instructiuni compuse.

Parametrii formali se declara dupa o sintaxa similara cu cea folosita in alte declaratii. Parametrii pot fi scalari, structuri, uniuni, pointeri sau referinte catre scalari, structuri sau uniuni, si pointeri catre functii sau clase. In C++ ultimii parametri pot avea valori implicite, prezentate sub forma unor initializatori.

Punctele de suspensie (...) indica o lista de parametri variabila.

Se pot trece punctele de suspensie dupa o sublista constanta ca in exemplu (ultima virgula poate lipsi in C++):

int func ( FILE *f, char *format, ... ) ;

Domeniul de valabilitate al parametrilor formali este blocul care defineste corpul functiei. Timpul lor de viata este automatic.

Singura clasa de memorare permisa in declaratiile parametrilor formali este register. Se pot folosi modificatorii const si volatile.

La apelul unei functii,

1) Modificatorii folositi la definitia functiei trebuie sa se potriveasca cu cei folositi la declaratia ei si la orice apel

catre acea functie.

2) O functie poate modifica liber parametrii formali dar acest lucru nu are nici un efect asupra parametrilor actuali cu exceptia parametrilor de tip referinta din C++.

Daca o functie este apelata fara a fi fost declarata sau definita in prealabil sau daca este vorba de o lista variabila de parametri atunci parametrii actuali de tipuri intregi 'scurte' (char, short, unsigned char si unsigned short) sint convertiti catre int respectiv unsigned.

Daca functia apelata beneficiaza de existenta unui prototip (rezultat dintr-o declaratie sau dintr-o definitie) atunci parametrii actuali sint convertiti la tipurile parametrilor formali (cu care trebuie sa fie compatibili).

Corespondenta dintre declaratia unei functii si definitia ei nu poate fi verificata de catre compilator decit daca amindoua sint in aceeasi unitate de compilare. In C++ se asigura ca editarea de legaturi este 'sigura' in ceea ce priveste tipurile functiilor (tipul unei functii C++ contine si informatia referitoare la tipurile parametrilor) deci inC++neconcordantele dintre definitia unei functii si apelul ei sint detectate de editorul de legaturi.

Structuri

O structura este untip derivat reprezentind o colectie de membri care sint identificabili prinnumele lor sub forma unor componente selectate.Tipurile de date ale membrilor pot fi oarecare cu citeva exceptii. In plus membrii unei structuri pot fi cimpuri de biti care nu sint permise in alta parte.

In C++ un tip structura este tratat ca untip clasa cu urmatoarele particularitati: modul de acces implicit este public si modul de acces implicit pentru clasa de baza este de asemenea public. Utilizatorul poate modifica modul de accesa la membrii structurii prin folosirea cuvintelor cheie public, private sau protected. In afara de aceste observatii nu este nici o diferenta intre structurile din C si cele dinC++.

Structurile se declara cu cuvintul cheie struct:

"struct" [nume_structura] ["{" lista_declaratii membri "}"]

ca in exemplul

struct mystruct { int i ; char c1, c2 ; } ;

struct mystruct s, *ps, arrs [10] ;

In acest exemplu tipul de date al lui s este 'struct mystruct' al lui ps este 'pointer catre struct mystruct' iar al lui arrs este 'tablou de struct mystruct'.

Numele structurii poate lipsi daca declaratia structurii nu este facuta decit pentru a declara niste variabile. Un nume de tip se poate declara cu typedef in aceeasi declaratie cu definirea structurii; se poate declara sau nu un nume de structura (de obicei nu este nevoie).

Membrii de structura sau uniune fara nume sint ignorati in timpul initializarii.

Tipurile de date ale membrilor structurii nu au decit urmatoarele doua restrictii:

1) tipul dedate al unui membru nu poate fi chiar structura incurs dedefinire; dar poate fi un pointer catre aceasta structura.

2) tipul de date al unui membru de structura nu poate fi 'functie' (numai in C++este permis asa ceva) dar poatefi 'pointer catre o functie'.

In C++se poate omite cuvintul struct atunci cind se face referire la tipul de date structura (daca s-a definit un nume pentru structura).

struct mystruct { int i ; char c1, c2 ; } ;

struct mystruct s1, s2 [] ;

mystruct *s3 ; // permis in C++

Este permis ca o functie sa intoarca o structura sau un pointer catre o structura. O structura poate fi transmisa ca parametru unei functii in urmatoarele feluri: direct (transfer prin valoare obisnuit); sub forma unui pointer; prin referinta (numai in C++).

Accesul la membrii structurii se face sub forma unor componente selectate; operatorii de selectie sint punct (.) si sageata (->).

Selectia cu ajutorul operatorului punct este metoda de baza; in conditiile exemplului de mai sus urmatoarele expresii desemneaza componente selectate:

s1 .i

s2 [ s1 .i ] .c2

Selectia cu operatorul sageata se face pornind de la un pointer catre structura; prin definitie s3 -> c1 este echivalent cu (*s3).c1 (trebuie sa tinem cont de prioritatile operatorilor).

Structurile de acelasi tip se pot atribui printr-o singura operatie; 'acelasi tip' inseamna 'acelasi typedef sau nume de structura sau declaratie de structura anonima'.

Membrii unei structuri pot fi aliniati la limita de cuvint (optiunea -a sau comanda corespunzatoare in mediul integrat) sau pot fi alocati contiguu. Daca se cere aliniere la limita de cuvint, aceasta se face astfel:

a) se presupune ca structura incepe la adresa para;

b) toti membri non-char sint aliniati la adrese pare;

c) structura este eventual lungita cu unoctet pentru a asigura o lungime para.

Numele de structuri sint plasate in acelasi spatiu de nume ca numele de uniuni si numele de enumerari (dar numele de enumerari declarate in interiorul unei structuri se gasesc in alt spatiu de nume in C++) deci numele de enumarari nu trebuie sa fie distincte de identificatorii aflati inalte spatii de nume (spatiul etichetelor spatiul numelor de variabile, functii si tipuri si spatiile numelor membrilor de structuri).

Un pointer catre o structura A poate apare in declaratia unui membru al altei structuri B inainte ca structura A sa fie definita. O astfel de situatie se numeste declaratie incompleta a structurii A si este permisa deoarece nu este nevoie de cunoasterea marimii structurii A pentru cunoasterea marimii unui pointer.

struct A ; // declaratie incompleta

struct B

{

struct A *pa ; // utilizarea unui pointer catre struct A

struct B *pb ;

} ;

struct A // definitia structurii A

{

int i ;

struct B *pb ;

} ;

Cimpuri de biti

Membrii de structura de tip int sau unsigned pot fi alocati in cimpuri de 1 pina la 16 biti.Bitii sint alocati incepind cu cel mai putin semnificativ bit al fiecarui cuvint de 16 biti. Sintaxa este:

tip [identificator] ":" largime ";"

Largimea cimpului trebuie sa fie o expresie intreaga constanta cuprinsa intre 0 si 16 (0 inseamna aliniere la urmatoarea limita de cuvint). Daca nu se specifica un nume pentru cimpul de biti cimpul este alocat dar nu este accesibil (se foloseste pentru alinieri).

struct special_word

{

int i :2 ;

unsigned j :5 ;

int :4 ;

int k :1 ;

unsigned m :4 ;

} ;

bitii 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

| | | | | | | | | | | | | | | | |

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

k

restrictie importanta asupra operatiilor care se pot face cu cimpurile de biti este aceea ca nu li se poate afla adresa cu ajutorul operatorului & (adresa unui bit nu are sens).

Uniuni

Uniunile corespund cu inregistrarile cu variante din alte limbaje de programare (Pascal, Modula-2, etc.); o uniune este un tip 'hibrid' valoarea variabilei uniune fiind valoarea membrului activ al uniunii, ceilalti membri fiind nedefiniti. Sintactic, definitia unui tip uniune seamana cu definitia unui tip structura cu diferenta ca indicatorul struct se inlocuieste cu union (sint permise si cimpuri de biti). Dimensiunea spatiului de memorie alocat uniunii este egala cu dimensiunea spatiului alocat celui mai mare membru. Accesul la membrii uniunii se face sub forma unor componente selectate folosind aceiasi operatori si aceleasi reguli ca in cazul structurilor.

Numele de uniuni respecta aceleasi reguli ca si numele de uniuni (spatiu de nume, utilizare etc.).

Exemplu:

union myunion

{

int i ;

double d ;

char c ;

} mu ;

sizeof ( myunion ) --> 8

sizeof ( mu ) --> 8

sizeof ( mu .i ) --> 2

sizeof ( mu .c ) --> 1

sizeof ( mu .d ) --> 8

Respectind conversiile necesare, un pointer catre o uniune este un pointer catre oricare dintre membrii ei:

(double *) & mu == & mu .d

In C++ uniunile NU SINT CONSIDERATE CLASE deci utilizarea specificatorilor de mod de acces (public, private, protected) este interzisa. Totusi, uniunile pot avea un constructor asociat si uniunile cu nume (nu si cele anonime) pot avea membri de tip 'functie'.

O uniune nu poate fi initializata decit prinintermediul primului sau membru declarat.

Enumerari

Tipurile de date enumerare sint folosite inprincipal pentru a da nume mnemonice unor constante intregi. In exemplul

enum days { sun,mon,tue,wed,thu,fri,sat } anyday ;

se defineste un nou tip intreg numit enum days, un numar de constante de acest tip (sun, mon, ...) cu valori de acest tip si se declara o variabila de tip enum days, numita anyday.

In prezenta optiunii -b (sau a comenzii corespunzatoare din mediul integrat) compilatorul are libertatea sa aloce 1 sau 2 octeti pentru o variabila de tip enumerare (in functie de valorile constantelor definite); valorile constantelor definite sint de tip unsigned char sau int. In C unei variabile de tip enumerare i se poate atribui orice valoare intreaga; in C++ nu i se poate atribui decit o valoare de acelasi tip. In C++ se poate omite cuvintul cheie enum in referinte ulterioare la tipul definit; numele de enumarari sint in acelasi spatiu ca si numele de structuri si uniuni. In C++ constantele de enumerare definite in interiorul unei clase (structuri sau uniuni) sint valabile numai in interiorul clasei respective.

enum days this_day ; // legal si in C si in C++

days another_day ; // legal numai in C++

Constantele de enumerare au implicit valori incepind cu 0 si crescind din1 in1 (sun= 0, mon= 1, ..., sat = 6). La definitia tipului orice constanta de enumerare poate fi eventual urmata de un initializator sub forma unei expresii intregi constante (pozitive sau negative) care stabileste valoarea constantei; constantele de enumerare urmatoare care nu au o valoare explicita cresc din1 in1.

Sint permise valori duplicate. Numele constantelor de enumerare se afla in acelasi spatiu de nume ca si numele de variabile, functii si tipuri. Valori de tip enumerare pot apare oriunde sint permise valori de tip intreg.

enum coins

{

penny = 1, // 1

tuppence, // 2

nickel = penny + 4, // 5

dime = 10, // 10

quarter = nickel * nickel // 25

} ;

EXPRESII

O expresie este un sir de operanzi, operatori si separatori care descrie o prelucrare. Mai jos se da sintaxa unei expresii:

expresie = lista_de_expresii .

lista_de_expresii = atribuire [ "," atribuire ]... .

atribuire = expresie_conditionala |

expresie_unara operator_atribuire atribuire .

operator_atribuire =

"=" | "*=" | "/=" | "%=" | "+=" | "-=" | "=" | "&=" | "^=" | "|="

.

expresie_conditionala =

expresie_SAU_logic [ "?" expresie ":" expresie_conditionala ] .

expresie_SAU_logic =

expresie_SI_logic [ "||" expresie_SI_logic ]... .

expresie_SI_logic =

expresie_SAU [ "&&" expresie_SAU ]... .

expresie_SAU =

expresie_SAU_EXCLUSIV [ "|" expresie_SAU_EXCLUSIV ]... .

expresie_SAU_EXCLUSIV =

expresie_SI [ "^" expresie_SI ]... .

expresie_SI = egalitate [ "&" egalitate ]... .

egalitate =

expresie_relationala

[ ( "==" | "!=" ) expresie_relationala ]... .

expresie_relationala =

expresie_deplasare

[ operator_relational expresie_deplasare ]... .

operator_relational = "=" .

expresie_deplasare =

expresie_aditiva [ ( "" ) expresie_aditiva ]... .

expresie_aditiva =

expresie_multiplicativa

[ ( "+" | "-" ) expresie_multiplicativa ]... .

expresie_multiplicativa =

expresie_pm [ operator_multiplicativ expresie_pm ]... .

operator_multiplicativ = "*" | "/" | "%" .

expresie_pm = expresie_conversie |

expresie_pm ".*" expresie_conversie | C++

expresie_pm "->*" expresie_conversie . C++

expresie_conversie = expresie_unara |

"(" tip ")" expresie_unara .

expresie_unara = expresie_postfix |

( "++" | "--" ) expresie_unara |

operator_unar expresie_conversie |

"sizeof" ( expresie_unara | "(" tip ")" ) |

expresie_alocare | C++

expresie_dealocare . C++

operator_unar = "&" | "*" | "+" | "-" | "~" | "!" .

expresie_alocare = C++

["::"] "new" [amplasare] tip_restrins [initializator] |

["::"] "new" [amplasare] "(" tip ")" [initializator] .

expresie_dealocare = C++

["::"] "delete" [ "[" expresie "]" ] expresie_conversie .

amplasare = "(" expresie ["," expresie]... ")" . C++

tip_restrins = specificatori_de_tip [declarator_restrins] . C++

declarator_restrins = C++

operator_ptr [declarator_restrins] |

declarator_restrins "[" [expresie] "]" .

expresie_postfix =

expresie_primara |

expresie_postfix "[" expresie "]" |

expresie_postfix "(" [ expresie ["," expresie]... ] ")" |

nume_tip_simplu "(" [ expresie ["," expresie]... ] ")" | C++

expresie_postfix "." nume |

expresie_postfix "->" nume |

expresie_postfix ( "++" | "--" ) .

expresie_primara =

literal |

nume |

"(" expresie ")" |

"this" | C++

"::" identificator | C++

"::" nume_functie_operator . C++

literal = constanta | sir_de_caractere .

nume = identificator |

nume_functie_operator | C++

nume_functie_conversie | C++

nume_calificat . C++

nume_calificat = nume_clasa "::" identificator |

nume_clasa "::" nume_functie_operator |

nume_clasa "::" nume_functie_conversie |

nume_clasa "::" [ "~" ] nume_clasa .

Expresiile sint evaluate corespunzator cu prioritatea si asociativitatea operatorilor care apar; utilizarea parantezelor modifica ordinea de evaluare a operatorilor. Expresiile pot avea ca rezultat o valoare stinga, o valoare dreapta sau nici o valoare si pot avea eventual efecte laterale.

Majoritatea operatorilor C pot fi supraincarcati in C++ adica se poate defini printr-o functie comportarea operatorilor atunci cind sint aplicati asupra unor operanzi de un tip clasa precizat (vezi capitolul 'C++'). Supraincarcarea nu poate modifica prioritatea asociativitatea si aritatea operatorului. Similar, inC++se pot defini reguli speciale de conversie intre tipurile clasa.

ORDINEA IN CARE SE EVALUEAZA OPERANZII UNUI OPERATOR NU ESTE DEFINITA, CU EXCEPTIA CAZURILOR IN CARE DESCRIEREA OPERATORULUI PRECIZEAZA ALTFEL

In consecinta valoarea expesiei

i = v [i++] ;

nu este cunoscuta, ea depinde de compilatorul utilizat si de gradul de optimizare pe care acesta il practica. Compilatorul are libertatea sa rearanjeze calculele in orice ordine doreste cu scopul de a obtine un cod obiect cit mai performant. Se pot folosi paranteze pentru a controla (partial) ordinea operatiilor; deexemplu in expresia a +( b +c ) se garanteaza ca b +c se va calcula inainte de a se aduna rezultatul cu a.

Depasirile intregi aparute inevaluarea expresiilor sint ignorate; depasirile si alte erori aparute incursul calculelor in virgula mobila pot fi tratate cu ajutorul functiilor matherr si signal.

Semantica operatorilor

InC++se pot supraincarca toti operatorii, cu exceptia operatorilor "." (selectia unui membru) "?" ... ":" (operatorul conditional), "::" si ".*" (specifici limbajului C++).

Operatori postfixati

[] operator de indexare (selectia unui element de tablou).

exp1[exp2] esteprindefinitieechivalentcu

* ((exp1) + (exp2))

() apel de functie.Valoarea expresiei

expresie_postfix ( lista_expresii )

este data de valoarea intoarsa de functia determinata de expresia_postfix apelata cu parametrii actuali determinati de lista de expresii optionala.

. selectia unui membru al unei structuri/uniuni

expresie_postfix .identificator

expresia_postfix trebuie sa fie de tip structura sau uniune

-> selectia unui membru dupa dereferentiere

expresie_postfix -> identificator

expresia_postfix trebuie sa fie de tip pointer catre o structura sau o uniune iar identificatorul trebuie sa fie numele unui membru al acelei structuri sau uniuni (la fel si la ".")

++ postincrementare

expresie_postfix ++

expresia_postfix trebuie sa fie de tip scalar (aritmetic sau pointer) si trebuie sa fie o valoare stinga modificabila.

Rezultatul expresiei este valoarea expresiei_postfix; dupa calcularea valorii se adauga 1 la expresia_postfix (se aplica regulile de la adunare).

-- postdecrementare

expresie_postfix --

expresia_postfix trebuie sa fie de tip scalar (aritmetic sau pointer) si trebuie sa fie o valoare stinga modificabila.

Rezultatul expresiei este valoarea expresiei_postfix; dupa calcularea valorii se scade 1 din expresia_postfix (se aplica regulile de la scadere).

Operatori unari

++ preincrement

++ expresie_unara

expresia_unara trebuie sa fie de tip scalar (aritmetic sau pointer) si trebuie sa fie o valoare stinga modificabila.Rezultatul expresiei este valoarea expresiei_unare dupa ce s-a adaugat 1 la expresia_unara (se aplica regulile de la adunare).

-- predecrementare

-- expresie_unara

expresia_unara trebuie sa fie de tip scalar (aritmetic sau pointer) si trebuie sa fie o valoare stinga modificabila.Rezultatul expresiei este valoarea expresiei_unare dupa ce s-a scazut 1 din expresia_unara (se aplica regulile de la scadere).

& calculul adresei

& expresie_conversie

Operandul lui trebuie sa fie numele unei functii sau unobiect care nu este un cimp de biti si care nu are clasa de memorare register. Daca tipul operandului este t, atunci tipul rezultatului este pointer catre t. Deoarece numele unei functii sau al unui tablou sint automat convertiti la tipul 'pointer catre ...' utilizarea operatorului in astfel de situatii

este redundanta si trebuie evitata.

* indirectare (dereferentiere)

* expresie_conversie

Tipul operandului trebuie sa fie pointer 'catre ...'. Daca ipul operandului este 'pointer catre functie ...' atunci

expresia *operand desemneaza o functie. Daca tipul operandului este 'pointer catre t' atunci expresia *operand este o valoare stinga de tipul t. Daca operandul are valoarea NULL atunci rezultatul indirectarii este nedefinit.

+ plus unar

+ expresie_conversie

Rezultatul este valoarea expresiei (eventual largita la int sau unsigned). Expresia trebuie sa fie de tip aritmetic.

- minus unar

- expresie_conversie

Rezultatul este valoarea cu semnschimbat a expresiei dupa o eventuala largire la int sau unsigned. Expresia trebuie sa fie de tip aritmetic.

~ negare bit cu bit

~ expresie_conversie

Expresia trebuiesa fie de un tipintreg. Rezultatul este valoarea expresiei cu toti bitii complementati; se fac in

prealabil conversiile uzuale (largiri) catre int sau unsigned.

! negare logica

! expresie_conversie

Expresia trebuie sa fie de tip scalar. Rezultatul este 0daca expresiaeste diferita de 0 (NULL in cazul pointerilor) si 1

in caz contrar.

sizeof marimea spatiului de memorie necesar

sizeof expresie_unara

sizeof ( tip )

Intoarce marimea spatiului de memorie necesar pentru memorareavalorilor de tipul citat (sau de tipul expresiei). Valoarea este de tip intreg (tipul size_t definit ca unsigned int in) si este data inbytes (1 byte este spatiul de memorie necesar pentru unobiect de tip char). Expresia care apare ca operand NU ESTE EVALUATA deci nu poate produce efecte laterale. Operatorul sizeof se poate folosi in directive ale preprocesorului (aceasta este o caracteristica a Turbo C++).

In C++ sizeoF aplicat unei clase derivate dintr-o clasa de baza are ca rezultat dimensiunea clasei de baza.

(tip) conversie de tip

(tip) expresie_unara

Converteste valoarea expresiei la tipul indicat. Trebuie ca sa aiba sens conversia (se pot converti orice tipuri aritmetice intre ele si orice tipuri pointer intre ele; in anumitesituatii se permite si conversia intre pointeri si intregi dar cu precautii -- numai valoarea intreaga 0 se poate sigur converti catre orice tip pointer).

Operatori multiplicativi

expresie_conversie [operator_multiplicativ expresie_conversie]...

Operatorii multiplicativi se aplica numai tipurilor aritmetice si aplica regulile obisnuite de conversie.

* inmultire

/ impartire (daca operanzii sint intregi (-a)/b = a/(-b) = -(a/b)

% restul impartirii intregi (operanzii trebuie sa fie de untip intreg)

Operatori aditivi

expresie_multiplicativa [op_aditiv expresie_multiplicativa]...

Operatorii aditivi +si - se pot aplica tipurilor aritmeticecu respectarea conversiilor obisnuite. Se pot aduna (scadea) intregi la (dintr-un) pointer in care caz la adresa care este valoarea pointerului se aduna (se scade) valoarea intregului inmultita cu sizeoF (tipul de baza al pointerului). Pentru ca rezultatul sa fie sigur corect trebuie ca pointerul sa contina adresa unui element dintr-untablou cu nelemente si intregul sa fie astfel ca indicele elementului a carui adresa este rezultatul operatiei sa fie cuprins intre 0 si n. Pointerul nu poate fi de tip 'pointer catre functie ...'.

Operatori de deplasare

expresie_deplasare =

expresie_aditiva |

expresie_deplasare ">" expresie_aditiva .

Operanzii trebuie sa fie de untip intreg. Deplasarea este logica daca operandul deplasat (cel dinstinga) este fara semnsi aritmetica daca operandul deplasat este cu semn.

8 1 = 4

8 >> -1 = nedefinit

Operatorii relationali

expresie_relationala op_relational expresie_deplasare

Operatorii relationali sint < (mai mic) (mai mare) si >= (mai mare sau egal). Operanzii trebuie sa fie sau amindoi de tip aritmetic sau amindoi pointeri catre obiecte (nu functii). Rezultatul este de tip intreg 0 daca relatia nu este satisfacuta sau 1 daca relatia este satisfacuta. Pentru ca sa aiba sens compararea pointeriloradresele trebuie sa fie adresele a doi membri din aceeasi structura, sau a doua elemente din acelasi tablou.

Operatori de egalitate

Operatorii de egalitate sint == (egal) si != (neegal). Se pot compara valori de tip aritmetic pointeri si pointeri cu

constanta intreaga 0 (NULL). Rezultatul este de tip int si anume1 daca se indeplineste conditia testata si 0 in caz

contrar. Inainte de comparatie au loc conversiile obisnuite.

Operatii logice pe biti

Operatorii pentru operatii logice pe biti sint (produs logic bit cu bit) ^ (suma modulo 2 bit cu bit) si & (suma logica bit cu bit). Operanzii trebuie sa fie de un tip intreg. Au loc conversiile obisnuite.

Operatii logice

Operatorii logici binari sint | (produs logic; rezultatul este 1 daca nici unul dintre operanzi nu este 0 sau NULL) si && (suma logica; rezultatul este 1 daca macar unul dintre operanzi nu este 0 sau NULL). Operanzii trebuie sa fie de tip scalar (aritmetic sau pointer). OPERATORII && SI | ISI EVALUEAZA OPERANZII DE LA STINGA SPRE DREAPTA PINA CIND SE POATE DEDUCE VALOAREA EXPRESIEI LOGICE (EVALUARE IN SCURT-CIRCUIT).

Operatorul conditional

expresie_SAU_logic ? expresie : expresie_conditionala

Daca expresia de dinaintea lui '?' nu este 0atunci seevalueaza expresia a doua altfel se evalueaza expresia a treia.

Rezultatul expresiei evaluate este si rezultatul intregii expresii. Exemplul urmator tipareste cifra (de la '0' la 'F') corespunzatoare valorii intregi n (de la 0 la 15):

printf ( "%c", n F () atunci F opereaza asupra lui *px. Incadrul lui f cuvintul cheie "this" denumeste o variabila locala de tip 'pointer catre clasa a carei membra este f'; valoarea variabilei this este un pointer catre instantierea princare a fost apelata functia.Incorpul functiei se poat face referiri directe la membrii clasei subintelegindu-se dereferentierea lui this (de exemplu incorpul lui f prin se intelege de fapt this -> y).

O functie membra a unei clase poate fi declarata in interiorul clasei si definita inalta parte sau definitia ei poate figura chiar in corpul clasei; inacest al doilea caz ea este automat considerata 'inline'. Si in primul caz functia poate fi declarata inline inmod explicit. Pentru functiile declarate inline explicit sau implicit compilatorul are libertatea sa genereze cod inline sau nu. Se recomanda sa se declare inline functiile mici care implementeaza actiunea opertorilor supraincarcati ca inexemplul:

int i ;

class X

{

public:

char *func (void) { return i ; }

char *i ;

} ;

Definitia functiei este echivalenta cu:

class X

{

public:

char *func (void) ;

char *i ;

} ;

inline char * X ::func (void) { return i ; }

Trebuie mentionat ca valoarea intoarsa de functia func este valoarea membrului i al clasei X ( deci i dinreturni ; este this -> i).

Pentru a intelege de ce asa stau lucrurile vezi mai jos despre domeniul de valabilitate al numelor membrilor unei clase.

Membrii unei clase declarati static au alte proprietati decit membrii obisnuiti. Pentru membrii obisnuiti exista cite unexemplar pentru fiecare instantiere a clasei; pentru membrii statici exista un singur exemplar si acesta poate fi accesat prin nume_clasa ::nume_membru chiar daca nici o instantiere a clasei nu a fost declarata sau creata inca. Membrii statici pot fi accesati si prin

mecanismul normal deci daca x este unobiect de clasa X si px un pointer catre clasa X iar s este un membru static atunci s poate fi accesat si prinx .s sau px -> s DAR X SAU PX NU SINT EVALUATI IN ACEST CAZ (se stie dinainte ca este vorba despre unicul s). O functie statica membra a unei clase poate fi apelata cu sau fara

referire la o instantiere a clasei; de aceea functiile statice membre ale unei clase nu au nici o variabila locala this si nu pot avea acces la membri non-statici fara a folosi operatorii de selectie . sau ->.

Cu exceptia functiilor inline functiile statice membre ale unei clase definite pe nivelul superficial au legare externa; functiile statice membre ale unei clase nu pot fi declarate virtual.

Declararea unui membru static al unei clase nu este o definitie deci acest membru trebuie definit inafara clasei pentru a aloca memorie si a-l initializa (acest lucru nu este necesar daca optiunea de initializare automata cu zero este activa). Membrii statici ai unei clase definite ininteriorul unei functii sint fara legare si nu pot fi initializati.

class X

{

static int x ;

} ;

int X::x = 1 ;

Principala utilizare a membrilor statici este aceea de a memora date comune tuturor instantierilor clasei (cite obiecte au fost create etc.). Membrii statici mai sint folositi pentru:

o a reduce numarul de identificatori vizibili in tot programul ;

o a explicita apartenenta logica a unor obiecte statice la o anumita clasa ;

o a permite controlul accesului la anumite nume.

Domeniul de valabilitate al membrilor unei clase

Intregul corp al functiilor membre se considera in domeniul de valabilitate al membrilor clasei (de aceea in exemplul de mai sus func intoarce valoarea membrului i al clasei X si nu valoarea variabilei globale i).

Membrii unei clase pot fi referiti prinfolosirea unor componente selectate (cu operatorii . si ->; operatorul -> poate fi eventu


Recommended