Capitolul 2.7. Conversii de tip

Vezi subiectul anterior Vezi subiectul urmator In jos

Capitolul 2.7. Conversii de tip

Mesaj  zooky la data de Mier Mar 18, 2009 11:46 am

Cind intr-o expresiie apar operanzi de mai multe tipuri, ei se convertesc intr-un tip comun, dupa un numar mic de reguli. In general, singurele conversii care se fac automat sint acelea cu sens , de exemplu convertirea unui numar intreg intr-un flotant in expresii de tipul f + i. Expresiile fara sens, de exemplu folosirea unui float ca indice de tablou, nu sint permise.In primul rind, char-i si int-i pot fi amestecati in expresiile aritmetice: orice char este convertit automat intr-un int. Aceasta permite o flexibilitate remarcabila in anumite tipuri de transformari de caractere. Exemplificam cu functia atoi, care converteste un sir de cifre in echivalentul lui numeric.

atoi(s) /* converteste un sir s in intreg */
char s[];
{
int i, n;
n = 0;
for (i = 0; s[i] >= '0' && s[i] <= '9' ; ++i)
n = 10 * n + s[i] - '0';
return(n);
}

Asa cum am vazut in Capitolul 1, expresia

s[i]-'0'

reprezinta valoarea numerica a caracterului aflat in s[i] deoarece valorile lui '0','1', etc formeaza un sir crescator pozitiv si contiguu.
Un alt exemplu de conversie intre char si int il constituie functia lower care transforma literele mari din setul de caractere ASCII in litere mici. Daca intrarea nu este o litera mare, functia o returneaza neschimbata:

lower(c) /* conversie ASCII litere mari in litere mici */
int c;
{
if (c >= 'A' && c <= 'Z')
return(c + 'a' - 'A');
else
return(c)
}

Aceasta functie este valabila numai pentru ASCII deoarece pe de o parte intre literele mari si literele mici exista o distanta fixata, ca valoare numerica, iar pe de alta parte ambele alfabete sint contigue - intre A si Z se gasesc numai litere.
Aceasta ultima observatie nu este valabila pentru setul de caractere EBCDIC (IBM 360/370), asa incit functia lower esueaza pentru aceste sisteme, ea va converti mai mult decit literele mari.
Exista o subtilitate in conversia caracterelor in intregi.
Limbajul nu specifica daca o variabila de tip char este o cantitate cu semn sau fara semn. Cind un char este convertit intr-un int, poate el produce un intreg negativ ? Din pacate, aceasta variaza de la calculator la calculator, reflectind diferentele arhitecturale. Pe anumite calculatoare (de exemplu PDP-11) un char al carui cel mai din stinga bit este 1 va fi convertit intr-un intreg negativ ("extensie de semn". Pe altele, un char este convertit intr-un int prin adaugarea de zerouri in partea stinga si astfel el este intodeauna pozitiv.
Definitia lui C asigura ca orice caracter din setul standard al masinii nu va fi niciodata negativ, asa ca aceste caractere pot fi folosite liber in expresii ca si cantitati pozitive. Dar modele arbitrare de biti memorate in variabile de tip character pot apare drept negative pe anumite calculatoare si drept pozitive pe altele.
Cea mai comuna aparitie a acestei situatii este cind pentru EOF se foloseste -1. Sa consideram codul:

char c;
c = getchar();
if (c == EOF)
...

Pe un calculator care nu face extensie de semn, c este intodeauna pozitiv deoarece el este un char, dar totusi EOF este negativ. In consecinta testul esueaza intodeauna. Pentru a evita aceasta, trebuie sa avem grija atunci cind folosim int in loc de char pentru orice variabila care primeste o valoare returnata de getchar.
Adevarata ratiune pentru utilizarea lui int in loc de char nu este legata cu nimic de posibila extensie de semn. Pur si simplu, getchar trebuie sa returneze toate caracterele posibile (astfel incit sa poate fi folosita pentru a citi o intrare arbitrara) si in plus, o valoare pentru EOF distincta. Astfel, aceasta valoare nu poate fi reprezentata ca si un char dar, in schimb, trebuie memorata ca si un int.
O alta forma utila de conversie de tip automata este aceea ca expresiile relationale de tipul i > j si expresiile logice conectate prin && si || se definesc a avea valoarea 1 pentru adevar si 0 pentru fals. Astfel, o asignare:

isdigit = c >= '0' && c <= '9';

pune pe isgit pe 1 daca c este o cifra si pe 0 daca nu. (In partea de test a lui if, while ,for, etc, "adevarat" inseamna "nonzero").

Conversiile aritmetice implicite lucreaza in mare masura cum ne asteptam. In general, daca un operator ca + sau * care are doi operanzi (un "operator binar") are operanzi de tipuri diferite, tipul "inferior" este promovat la tipul "superior" inainte de executia operatiei. Rezultatul insusi este de tipul superior. Mai precis, pentru fiecare operator aritmetic, se aplica urmatoarea secventa de reguli de conversie:

char si short se convertesc in int iar float este convertit in double.

Apoi, daca un operand este double , celalalt este convertit in double iar rezultatul este double.

Altfel, daca un operand este long, celalalt este convertit in long iar rezultatul este long.

Altfel, daca un operand este unsigned, celalalt este convertit inunsigned, iar rezultatul este unsigned.

Altfel, operanzii trebuie sa fie int, iar rezultatul este int.

Sa notam ca toti float dintr-o expresie sint convertiti in double; orice calcul flotant in C este facut in dubla precizie.

Conversiile se fac in asignari; valoarea partii drepte este convertita la tipul din stinga, care este tipul rezultatului. Un caracter este convertit intr-un int fie cu extensie de semn, fie nu, asa cum s-a descris mai sus. Operatia inversa, int in char, se comporta bine, pur si simplu, bitii de ordin superior in exces sint eliminati. Astfel, in:

int i;
char c;
i = c;
c = i;

valoarea lui c ete neschimbata. Acesta este adevarat si cind extensia de semn este implicita si cind nu este implicita.

Daca x este float iar i este int, atunci:

x = i;
si
i = x;

provoaca amindoua conversii; float in int provoaca trunchierea oricarei parti fractionare. double este convertit in float prin rotunjire. Intregii lungi sint convertiti in scurti sau in char prin pierderea bitilor de ordin superior in exces.
Deoarece argumentul unei functii este o expresie, conversia de tip are loc deasemenea si cind argumentele sint
pasate functiei in particular, char si short devin int, iar float devine double. Iata de ce am declarat argumentul functiei ca fiind int si double chiar cind functia este apelata cu char si float.
In final, conversia explicita de tip poate fi fortata in orice expresie cu o constructie numita "distribuire"(cast). In constructia:

(numedetip) expresie

sus. Semnificatia precisa a unei distribuiri este de fapt ca si daca o expresie ar fi asignata la o variabila de tipul specificat, care este apoi folosita in locul intregii constructii. De exemplu, rutina din biblioteca sqrt are nevoie de un argument double si va produce nonsens daca i se da sa minuiasca altceva.
Astfel, daca n este un intreg:

sqrt((double) n)

il converteste pe n in double inainte de a-l pasa lui sqrt. (De notat ca distribuirea produce valoarea n in tipul potrivit; continutul efectiv al lui n nu este alterat ). Operatorul de distribuire are acceasi pondere ca si alti operatori unari, asa cum apare si in tabelul recapitulativ de la sfirsitul capitolului.

Exercitiul 2.2. Scrieti o functie htoi(s) care converteste un sir de cifre hexazecimale in valoarea sa intreaga echivalenta. Cifrele sint de la 0 la 9, literele de la a la f si de la A la F.
avatar
zooky
Moderator
Moderator

Numarul mesajelor : 147
Data de inscriere : 15/03/2009
Varsta : 24
Localizare : Cernatesti City

Vezi profilul utilizatorului http://e-learning.forumhit.ro

Sus In jos

Vezi subiectul anterior Vezi subiectul urmator Sus


 
Permisiunile acestui forum:
Nu puteti raspunde la subiectele acestui forum