MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Conversia tipurilor de date de bază

Atunci când discutăm despre tipurile de date, am menționat ce valori poate avea un anumit tip și cât spațiu de memorie poate ocupa. În tema anterioară am discutat despre operațiile aritmetice. Acum vom aplica operația de adunare la date de tipuri diferite:

byte a = 4;
int b = a + 70;

Rezultatul acestei operații este numărul 74, așa cum era de așteptat.

Dar acum vom încerca să aplicăm adunarea la două obiecte de tip byte:

byte a = 4;
byte b = a + 70;  // eroare

Aici s-a schimbat doar tipul variabilei care primește rezultatul adunării - de la int la byte. Totuși, când încercăm să compilăm programul, vom primi o eroare la compilare. Dacă lucrăm în Visual Studio, mediul va sublinia a doua linie cu o linie ondulată roșie, indicând că există o eroare.

De ce apare eroarea?

În operațiile aritmetice trebuie să luăm în considerare intervalul de valori pe care le poate stoca un anumit tip. În acest caz, numărul 74, pe care ne așteptăm să-l obținem, se încadrează în intervalul de valori pentru tipul byte, totuși obținem o eroare.

Motivul este că operația de adunare (și scădere) returnează o valoare de tip int dacă în operație sunt implicate tipuri de date întregi cu dimensiuni mai mici sau egale cu int (adică tipuri byte, short, int).

Prin urmare, rezultatul operației a + 70 va fi un obiect care ocupă 4 octeți în memorie. Apoi încercăm să atribuim acest obiect variabilei b, care este de tip byte și ocupă 1 octet în memorie.

Pentru a rezolva această problemă, trebuie să aplicăm operația de conversie a tipurilor. Operația de conversie a tipurilor implică specificarea în paranteze a tipului la care trebuie convertită valoarea:

(byte)(valoare_pentru_conversie);

Să modificăm exemplul anterior, aplicând operația de conversie a tipurilor:

byte a = 4;
byte b = (byte)(a + 70);

Conversii de extindere și restrângere

Conversiile pot fi de extindere (widening) și de restrângere (narrowing). Conversiile de extindere măresc dimensiunea obiectului în memorie. De exemplu:

byte a = 4;             // 0000100
ushort b = a;           // 0000000000000100

În acest caz, variabilei de tip ushort i se atribuie o valoare de tip byte. Tipul byte ocupă 1 octet (8 biți), iar valoarea variabilei a în formă binară poate fi reprezentată astfel:

00000100

Valoarea de tip ushort ocupă 2 octeți (16 biți). La atribuirea valorii variabilei b, valoarea variabilei a este extinsă la 2 octeți:

0000000000000100

Conversii de restrângere

Conversiile de restrângere reduc dimensiunea valorii la un tip cu o dimensiune mai mică. În al doilea exemplu din articol am avut de-a face cu conversii de restrângere:

ushort a = 4;
byte b = (byte)a;

Aici variabilei b, care ocupă 8 biți, i se atribuie o valoare ushort, care ocupă 16 biți. Astfel, din:

0000000000000100

obținem:

00000100

Conversii implicite și explicite

Conversii implicite

În cazul conversiilor de extindere, compilatorul efectuează automat conversiile, adică acestea sunt conversii implicite (implicit conversion). Aceste conversii nu cauzează probleme. Totuși, este important să înțelegem mecanismul general al acestor conversii.

Dacă se efectuează o conversie de la un tip fără semn cu dimensiuni mai mici la un tip fără semn cu dimensiuni mai mari, se adaugă biți suplimentari cu valoarea 0. Aceasta se numește extindere cu zerouri (zero extension).

byte a = 4;             // 0000100
ushort b = a;           // 0000000000000100

Dacă se efectuează o conversie la un tip cu semn, reprezentarea binară este completată cu zerouri dacă numărul este pozitiv și cu unități dacă numărul este negativ. Ultimul bit al numărului conține bitul de semn - 0 pentru numere pozitive și 1 pentru numere negative. La extindere, bitul de semn este copiat în biții adăugați.

Conversie a unui număr pozitiv:

sbyte a = 4;            // 0000100
short b = a;            // 0000000000000100

Conversie a unui număr negativ:

sbyte a = -4;           // 1111100
short b = a;            // 1111111111111100

Conversii explicite

La conversiile explicite (explicit conversion) trebuie să aplicăm manual operația de conversie (operația ()). Esența operației de conversie constă în specificarea în paranteze a tipului la care trebuie convertită valoarea:

int a = 4;
int b = 6;
byte c = (byte)(a + b);

Conversiile de extindere de la tipuri cu dimensiuni mai mici la tipuri cu dimensiuni mai mari sunt realizate implicit de către compilator. Acestea pot fi următoarele lanțuri de conversii:

  • byte -> short -> int -> long -> decimal
  • int -> double
  • short -> float -> double
  • char -> int

Toate conversiile automate sigure pot fi descrise în următorul tabel:

În celelalte cazuri, trebuie să utilizăm conversii explicite.

De asemenea, este de remarcat faptul că, deși atât double cât și decimal pot stoca date fracționare, iar decimal are o precizie mai mare decât double, totuși valoarea double trebuie convertită explicit la tipul decimal:

double a = 4.0;
decimal b = (decimal)a;

Pierderea preciziei datelor

Să analizăm o altă situație, de exemplu, următoarea:

int a = 33;
int b = 600;
byte c = (byte)(a + b);
Console.WriteLine(c);   // 121

Rezultatul va fi numărul 121, deoarece numărul 633 nu se încadrează în intervalul permis pentru tipul byte, iar biții superiori vor fi trunchiați. Astfel, obținem numărul 121. Prin urmare, la conversii trebuie să ținem cont de acest lucru. În acest caz, putem fie să folosim astfel de numere a și b, încât suma lor să fie mai mică sau egală cu 255, fie să alegem un alt tip de date în loc de byte, de exemplu, int.

← Lecția anterioară Lecția următoare →