Limbajul C prezinta un numar mare de operatori, caracterizati prin diferite
nivele de prioritate sau precedenta. k2v15vr
In acest capitol descriem operatorii in ordinea descrescatoare a
precedentei lor. Operatorii descrisi in acelasi paragraf au aceeasi precedenta.
Vom specifica de fiecare data daca asociativitatea este la stinga sau
la dreapta.
Expresiile combina variabile si constante pentru a produce valori noi si le
vom introduce pe masura ce vom prezenta operatorii.
4.1. Expresii primare
Expresie-primara: identificator constanta sir
(expresie) expresie-primara aexpresiei expresie-primara (lista-expresii?opt?) valoare-stinga . identificator expresie-primara -? identificator
Lista-expresii: expresie lista-expresii, expresie
Un identificator este o expresie-primara, cu conditia ca el sa fi fost declarat
corespunzator. Tipul sau este specificat in declaratia sa.
Daca tipul unui identificator este „masiv de ...”, atunci valoarea
expresiei-identificator este un pointer la primul obiect al masivului, iar tipul
expresiei este „pointer la ...”. Mai mult, un identificator de masiv
nu este o expresie valoare-stinga.
La fel, un identificator declarat de tip „functie care returneaza ...”,
care nu apare pe pozitie de apel de functie este convertit la „pointer
la functie care returneaza ...”.
O constanta este o expresie-primara. Tipul sau poate fi int, long sau double.
Constantele caracter sint de tip int, constantele flotante sint
de tip long double.
Un sir este o expresie-primara. Tipul sau original este „masiv de caractere”,
dar urmind aceleasi reguli descrise mai sus pentru identificatori, acesta
este modificat in „pointer la caracter” si rezultatul este
un pointer la primul caracter al sirului. Exista citeva exceptii in
anumite initializari (vezi paragraful 5.4).
O expresie intre paranteze rotunde este o expresie-primara, al carei tip
si valoare sint identice cu cele ale expresiei din interiorul parantezelor
(expresia din paranteze poate fi si o valoare-stinga).
O expresie-primara urmata de o expresie intre paranteze patrate este o
expresie-primara. Sensul intuitiv este de indexare. De obicei expresia-primara
are tipul „pointer la ...”, expresia-indice are tipul int, iar rezultatul
are tipul „...”. O expresie de forma E1aE2i este identica (prin
definitie) cu *((E1)+(E2)), unde * este operatorul de indirectare.
Un apel de functie este o expresie-primara. Ea consta dintr-o expresie-primara
urmata de o pereche de paranteze rotunde, care contin o lista-expresii separate
prin virgule. Lista-expresii constituie argumentele reale ale functiei; aceasta
lista poate fi si vida. Expresia-primara trebuie sa fie de tipul „functie
care returneaza ...”, iar rezultatul apelului de functie va fi de tipul
„...”.
Inaintea apelului, oricare argument de tip float este convertit la tipul
double, oricare argument de tip char sau short este convertit la tipul int.
Numele de masive sint convertite in pointeri la inceputul
masivului. Nici o alta conversie nu se efectueaza automat.
Daca este necesar pentru ca tipul unui argument actual sa coincida cu cel al
argumentului formal, se va folosi un cast (vezi sectiunea 3.4).
Sint permise apeluri recursive la orice functie.
O valoare-stinga urmata de un punct si un identificator este o expresie-primara.
Valoarea-stinga denumeste o structura sau o reuniune (vezi capitolul 10)
iar identificatorul denumeste un membru din structura sau reuniune. Rezultatul
este o valoare-stinga care se refera la membrul denumit din structura
sau reuniune.
O expresie-primara urmata de o sageata (constituita dintr-o liniuta si semnul
? urmata de un identificator este o expresie-primara. Prima expresie trebuie
sa fie un pointer la o structura sau reuniune, iar identificatorul trebuie sa
fie numele unui membru din structura sau reuniunea respectiva. Rezultatul este
o valoare-stinga care se refera la membrul denumit din structura sau reuniunea
catre care indica expresia pointer.
Expresia E1??E2 este identica din punctul de vedere al rezultatului cu (*E1).
E2
Descriem in continuare operatorii limbajului C impreuna cu expresiile
care se pot constitui cu acesti operatori.
4.2. Operatori unari
Toti operatorii unari au aceeasi precedenta, iar expresiile unare se grupeaza
de la dreapta la stinga.
Expresie-unara:
* expresie
& valoare-stinga
? expresie
! expresie
I expresie
++ valoare-stinga
-- valoare-stinga valoare-stinga ++ valoare-stinga - (nume-tip) expresie sizeof (nume-tip)
Operatorul unar * este operatorul de indirectare. Expresia care-l urmeaza
trebuie sa fie un pointer, iar rezultatul este o valoare-stinga care se
refera la obiectul catre care indica expresia. Daca tipul expresiei este „pointer
la ...” atunci tipul rezultatului este „...”. Acest operator
trateaza operandul sau ca o adresa, face acces la ea si ii obtine continutul.
Exemplu: instructiunea y = *px; atribuie lui y continutul adresei catre care
indica px.
Operatorul unar & este operatorul de obtinere a adresei unui obiect sau
de obtinere a unui pointer la obiectul respectiv. Operandul este o valoare-stinga
iar rezultatul este un pointer la obiectul referit de valoarea-stinga.
Daca tipul valorii-stinga este „...” atunci tipul rezultatului
este „pointer la ...”.
Exemplu. Fie x o variabila de tip int si px un pointer creat intr-un anumit
fel (vezi capitolul 9). Atunci prin instructiunea px = &x; se atribuie variabilei de tip „pointer la int” px adresa variabilei
x; putem spune acum ca px indica spre x. Secventa: px = &x; y = *px; este echivalenta cu y = x;
Operatorul & poate fi aplicat numai la variabile si la elemente de masiv.
Constructii de forma &(x+1) si &3 nu sint admise. De asemenea
nu se admite ca variabila sa fie de clasa register.
Operatorul unar & ajuta la transmiterea argumentelor de tip adresa in
functii.
Operatorul unar - este operatorul de negativare. Operandul sau este o expresie,
iar rezultatul este negativarea operandului. In acest caz sint aplicate
conversiile aritmetice obisnuite. Negativarea unui intreg de tip unsigned
se face scazind valoarea sa din 2n, unde n este numarul de biti rezervati
tipului int.
Operatorul unar ! este operatorul de negare logica. Operandul sau este o expresie,
iar rezultatul sau este 1 sau 0 dupa cum valoarea operandului este 0 sau diferita
de zero. Tipul rezultatului este int. Acest operator este aplicabil la orice
expresie de tip aritmetic sau la pointeri.
Operatorul unar I (tilda) este operatorul de complementare la unu. El converteste
fiecare bit 1 la 0 si invers. El este un operator logic pe biti.
Operandul sau trebuie sa fie de tip intreg. Se aplica conversiile aritmetice
obisnuite.
Operatorul unar ++ este operatorul de incrementare. Operandul sau este o valoare-stinga.
Operatorul produce incrementarea operandului cu 1. Acest operator prezinta un
aspect deosebit deoarece el poate fi folosit ca un operator prefix (inaintea
variabilei: ++n) sau ca un operator postfix (dupa variabila: n++). In
ambele cazuri efectul este incrementarea lui n. Dar expresia ++n incrementeaza
pe n inainte de folosirea valorii sale, in timp ce n++ incrementeaza
pe n dupa ce valoarea sa a fost utilizata. Aceasta inseamna ca in
contextul in care se urmareste numai incrementarea lui n, oricare constructie
poate fi folosita, dar intr-un context in care si valoarea lui n
este folosita ++n si n++ furnizeaza doua valori distincte.
Exemplu: daca n este 5, atunci x = n++ ; atribuie lui x valoarea 5 x = ++n ; atribuie lui x valoarea 6
In ambele cazuri n devine 6.
Rezultatul operatiei nu este o valoare-stinga, dar tipul sau este tipul
valorii-stinga.
Operatorul unar -- este operatorul de decrementare. Acest operator este analog
cu operatorul ++ doar ca produce decrementarea cu 1 a operandului.
Operatorul (nume-tip) este operatorul de conversie de tip. Prin nume-tip intelegem
unul dintre tipurile fundamentale admise in C. Operandul acestui operator
este o expresie. Operatorul produce conversia valorii expresiei la tipul denumit.
Aceasta constructie se numeste cast.
Operatorul sizeof furnizeaza dimensiunea in octeti a operandului sau.
Aplicat unui masiv sau structuri, rezultatul este numarul total de octeti din
masiv sau structura. Dimensiunea se determina in momentul compilarii,
din declaratiile obiectelor din expresie. Semantic, aceasta expresie este o
constanta intreaga care se poate folosi in orice loc in care
se cere o constanta. Cea mai frecventa utilizare o are in comunicarea
cu rutinele de alocare a memoriei sau rutinele I/O sistem.
Operatorul sizeof poate fi aplicat si unui nume-tip intre paranteze. In
acest caz el furnizeaza dimensiunea in octeti a unui obiect de tipul indicat.
Constructia sizeof(nume-tip) este luata ca o unitate, astfel ca expresia sizeof(nume-tip)-2 este acelasi lucru cu
(sizeof(nume-tip))-2
4.3. Operatori multiplicativi
Operatorii multiplicativi * / si % sint operatori aritmetici binari
si se grupeaza de la stinga la dreapta.
Expresie-multiplicativa: expresie * expresie expresie / expresie expresie % expresie
Operatorul binar * indica inmultirea. Operatorul este asociativ, dar
in expresiile in care apar mai multi operatori de inmultire,
ordinea de evaluare nu se specifica. Compilatorul rearanjeaza chiar si un calcul
cu paranteze. Astfel a*(b*c) poate fi evaluat ca (a*b)*c. Aceasta nu implica
diferente, dar daca totusi se doreste o anumita ordine, atunci se vor introduce
variabile temporare.
Operatorul binar / indica impartirea. Cind se impart doua
numere intregi pozitive, trunchierea se face spre zero; daca unul dintre
operanzi este negativ atunci trunchierea depinde de sistemul de calcul.
Operatorul binar % furnizeaza restul impartirii primei expresii la cea
de a doua. Operanzii nu pot fi de tip float. Restul are totdeauna semnul deimpartitului.
Totdeauna (a/b)*b+a%b este egal cu a (daca b este diferit de 0). Sint
executate conversiile aritmetice obisnuite.
4.4. Operatori aditivi
Operatorii aditivi + si - sint operatori aritmetici binari si se grupeaza
de la stinga la dreapta. Se executa conversiile aritmetice obisnuite,
Expresie-aditiva: expresie + expresie expresie - expresie
Operatorul binar + produce suma operanzilor sai. El este asociativ si expresiile
care contin mai multi operatori pot fi rearanjate la fel ca in cazul operatorului
de inmultire.
Operatorul binar - produce diferenta operanzilor sai.
4.5. Operatori de deplasare
Operatorii de deplasare << si >> sint operatori logici pe
biti. Ei se grupeaza de la stinga la dreapta.
Expresie-deplasare: expresie << expresie expresie >> expresie
Operatorul << produce deplasarea la stinga a operandului din stinga
cu un numar de pozitii binare dat de operandul din dreapta.
Operatorul >> produce deplasarea la dreapta a operandului din stinga
cu un numar de pozitii binare dat de operandul din dreapta.
In ambele cazuri se executa conversiile aritmetice obisnuite asupra operanzilor,
fiecare dintre ei trebuind sa fie de tip intreg. Operandul din dreapta
este convertit la int; tipul rezultatului este cel al operandului din stinga.
Rezultatul este nedefinit daca operandul din dreapta este negativ sau mai mare
sau egal cu lungimea obiectului, in biti. Astfel valoarea expresiei E1<<E2
este E1 (interpretata ca si configuratie de biti) deplasata la stinga
cu E2 pozitii bit; bitii eliberati devin zero. Expresia E1>>E2 este E1
deplasata la dreapta cu E2 pozitii binare. Deplasarea la dreapta este logica
(bitii eliberati devin 0) daca E1 este de tip unsigned; altfel ea este aritmetica
(bitii eliberati devin copii ale bitului semn).
Exemplu: x<<2 deplaseaza pe x la stinga cu 2 pozitii, bitii eliberati
devin 0; aceasta este echivalent cu multiplicarea lui x cu 4.
4.6. Operatori relationali
Operatorii relationali <, >, <=, >= se grupeaza de la stinga
la dreapta.
Expresie-relationala: expresie < expresie expresie > expresie expresie <= expresie expresie >= expresie
Operatorii < (mai mic), > (mai mare), <= (mai mic sau egal) si >=
(mai mare sau egal) produc valoarea 0 daca relatia specificata este falsa si
1 daca ea este adevarata.
Tipul rezultatului este int. Se executa conversiile aritmetice obisnuite. Acesti
operatori au precedenta mai mica decit operatorii aritmetici, astfel ca
expresia i<x-1 se considera i<(x-1) asa dupa cum ne asteptam.
4.7. Operatori de egalitate
Expresie-egalitate: expresie == expresie expresie != expresie
Operatorii == (egal cu) si != (diferit de) sint analogi cu operatorii
relationali, dar precedenta lor este mai mica. Astfel a<b == c<d este
1, daca a<b si c<d au aceeasi valoare de adevar.
4.8. Operatorul SI pe biti
Expresie-SI: expresie & expresie
Operatorul & este operatorul „SI” logic pe biti. El este asociativ
si expresiile care contin operatorul & pot fi rearanjate. Rezultatul este
functia logica „SI” pe biti aplicata operanzilor sai. Operatorul
se aplica numai la operanzi de tipuri intregi. Legea dupa care functioneaza
este:
& 0 1
0 0 0
1 0 1
Operatorul & este deseori folosit pentru a masca o anumita multime de
biti: de exemplu: c = n & 0177; pune pe zero toti bitii afara de ultimii 7 biti de ordin inferior ai lui n,
fara a afecta continutul lui n.
4.9. Operatorul SAU-exclusiv pe biti
Expresie-SAU-exclusiv: expresie ^ expresie
Operatorul ^ este operatorul „SAU-exclusiv” logic pe biti. El
este asociativ si expresiile care-l contin pot fi rearanjate. Rezultatul este
functia logica „SAU-exclusiv” pe biti aplicata operanzilor sai.
Operatorul se aplica numai la operanzi de tipuri intregi. Legea dupa care
functioneaza este:
^ 0 1
0 0 1
1 1 0
4.10. Operatorul SAU-inclusiv pe biti
Expresie-SAU-inclusiv: expresie | expresie
Operatorul | este operatorul „SAU-inclusiv” logic pe biti. El
este asociativ si expresiile care-l contin pot fi rearanjate. Rezultatul este
functia logica „SAU-inclusiv” pe biti aplicata operanzilor sai.
Operatorul se aplica numai la operanzi de tipuri intregi. Legea dupa care
functioneaza este:
| 0 1
0 0 1
1 1 1
Operatorul | este folosit pentru a pozitiona biti; de exemplu: x = x | MASK; pune pe 1 toti bitii din x care corespund la biti pozitionati pe 1 din MASK.
Se efectueaza conversiile aritmetice obisnuite.
4.11. Operatorul SI-logic
Expresie-SI-logic: expresie && expresie
Operatorul && este operatorul „SI-logic” si el se grupeaza
de la stinga la dreapta. Rezultatul este 1 daca ambii operanzi sint
diferiti de zero si 0 in rest. Spre deosebire de operatorul SI pe biti
&, operatorul SI-logic && garanteaza o evaluare de la stinga
la dreapta; mai mult, al doilea operand nu este evaluat daca primul operand
este 0.
Operanzii nu trebuie sa aiba in mod obligatoriu acelasi tip, dar fiecare
trebuie sa aiba unul dintre tipurile fundamentale sau pointer. Rezultatul este
totdeauna de tip int.
4.12. Operatorul SAU-logic
Expresie-SAU-logic: expresie || expresie
Operatorul || este operatorul „SAU-logic” si el se grupeaza de
la stinga la dreapta. Rezultatul este 1 daca cel putin unul dintre operanzi
este diferit de zero si 0 in rest.
Spre deosebire de operatorul SAU-inclusiv pe biti |, operatorul SAU-logic ||
garanteaza o evaluare de la stinga la dreapta; mai mult, al doilea operand
nu este evaluat daca valoarea primului operand este diferita de zero.
Operanzii nu trebuie sa aiba in mod obligatoriu acelasi tip, dar fiecare
trebuie sa aiba unul dintre tipurile fundamentale sau pointer. Rezultatul este
totdeauna de tip int.
4.13. Operatorul conditional
Expresie-conditionala: expresie ? expresie : expresie
Operatorul conditional ? este un operator ternar. Prima expresie se evalueaza
si daca ea este diferita de zero sau adevarata, rezultatul este valoarea celei
de-a doua expresii, altfel rezultatul este valoarea expresiei a treia. De exemplu
expresia: z = (a>b) ? a : b; calculeaza maximul dintre a si b si il atribuie lui z. Se evalueaza mai
intii prima expresie a>b. Daca ea este adevarata se evalueaza
a doua expresie si valoarea ei este rezultatul operatiei, aceasta valoare se
atribuie lui z. Daca prima expresie nu este adevarata atunci z ia valoarea lui
b.
Expresia conditionala poate fi folosita peste tot unde sintaxa cere o expresie.
Daca este posibil, se executa conversiile aritmetice obisnuite pentru a aduce
expresia a doua si a treia la un tip comun; daca ambele expresii sint
pointeri de acelasi tip, rezultatul are si el acelasi tip; daca numai o expresie
este un pointer, cealalta trebuie sa fie constanta 0, iar rezultatul este de
tipul pointerului. Intotdeauna numai una dintre expresiile a doua si a
treia este evaluata.
Daca f este flotant si n intreg, atunci expresia
(h>0)? f : n este de tip double indiferent daca n este pozitiv sau negativ. Parantezele nu
sint necesare deoarece precedenta operatorului ?: este mai mica, dar ele
pot fi folosite pentru a face expresia conditionala mai vizibila.
4.14. Operatori de atribuire
Exista mai multi operatori de atribuire, care se grupeaza toti de la dreapta
la stinga. Operandul sting este o valoare-stinga, operandul
drept este o expresie. Tipul expresiei de atribuire este tipul operandului sting.
Rezultatul este valoarea memorata in operandul sting dupa ce atribuirea
a avut loc. Cele doua parti ale unui operator de atribuire compus sint
unitati lexicale (simboluri) distincte.
Expresie-atribuire: valoare-stinga = expresie valoare-stinga op= expresie unde op poate fi unul din operatorii +, -, *, /, %, <<, >>, &,
^, |.
Intr-o atribuire simpla cu =, valoarea expresiei inlocuieste pe
cea a obiectului referit de valoare-stinga. Daca ambii operanzi au tip
aritmetic, atunci operandul drept este convertit la tipul operandului sting
inainte de atribuire.
Expresiile de forma E1 op= E2 se interpreteaza ca fiind echivalente cu expresiile
de forma E1 = E1 op E2; totusi E1 este evaluata o singura data.
Exemplu: expresia x *= y+1 este echivalenta cu x = x * (y+1) si nu cu x = x * y + 1
Pentru operatorii += si -=, operandul sting poate fi si un pointer,
in care caz operandul din dreapta este convertit la intreg (vezi
capitolul 9). Toti operanzii din dreapta si toti operanzii din stinga
care nu sint pointeri trebuie sa fie de tip aritmetic.
Atribuirea prescurtata este avantajoasa in cazul cind in membrul
sting avem expresii complicate, deoarece ele se evalueaza o singura data.
4.15. Operatorul virgula
Expresie-virgula: expresie , expresie
O pereche de expresii separate prin virgula se evalueaza de la stinga
la dreapta si valoarea expresiei din stinga se neglijeaza. Tipul si valoarea
rezultatului sint cele ale operandului din dreapta. Acesti operatori se
grupeaza de la stinga la dreapta. In contextele in care virgula
are un sens special, (de exemplu intr-o lista de argumente reale ale unei
functii si lista de initializare), operatorul virgula descris aici poate aparea
numai in paranteze. De exemplu functia: f(a,(t=3,t+2),c) are trei argumente, dintre care al doilea are valoarea 5. Expresia acestui argument
este o expresie virgula. In calculul valorii lui se evalueaza intii
expresia din stinga si se obtine valoarea 3 pentru t, apoi cu aceasta
valoare se evalueaza a doua expresie si se obtine t?5. Prima valoare a lui t
se pierde.
4.16. Precedenta si ordinea de evaluare
Tabelul de la sfirsitul acestei sectiuni constituie un rezumat al regulilor
de precedenta si asociativitate ale tuturor operatorilor.
Operatorii din aceeasi linie au aceeasi precedenta; liniile sint scrise
in ordinea descrescatoare a precedentei, astfel de exemplu operatorii
*, / si % au toti aceeasi precedenta, care este mai mare decit aceea a
operatorilor + si -.
Dupa cum s-a mentionat deja, expresiile care contin unul dintre operatorii asociativi
sau comutativi (*, +, &, ^, |) pot fi rearanjate de compilator chiar daca
contin paranteze. In cele mai multe cazuri aceasta nu produce nici o diferenta;
in cazurile in care o asemenea diferenta ar putea aparea pot fi
utilizate variabile temporare explicite, pentru a forta ordinea de evaluare.
Limbajul C, ca si multe alte limbaje, nu specifica in ce ordine sint
evaluati operanzii unui operator. De exemplu intr-o instructiune de forma: x = f() + g(); f poate fi evaluata inainte sau dupa evaluarea lui g; daca f sau g altereaza
o variabila externa de care cealalta depinde, x poate depinde de ordinea de
evaluare. Din nou rezultate intermediare trebuie memorate in variabile
temporare pentru a asigura o secventa particulara.
Operator Asociativitate
() ai -> . stinga la dreapta
! ++ -- - (tip) * & sizeof dreapta la stinga
* / % stinga la dreapta
+ - stinga la dreapta
<< >> stinga la dreapta
< <= > >= stinga la dreapta
== != stinga la dreapta
& stinga la dreapta
^ stinga la dreapta
| stinga la dreapta
&& stinga la dreapta
|| stinga la dreapta
?: dreapta la stinga
= op= dreapta la stinga , stinga la dreapta