Pretvaranje tipova podataka

U računarstvu, pretvaranje tipova podataka (engl. type conversion,[1][2] type casting,[1][3] type coercion[3] ili type juggling[4][5] ) način je promjene tipa podatka neke varijable unutar programskog koda. Pretvorba može biti implicitna (automatska) ili eksplicitna (zatražena),[1][6] a novi podatak može biti pretvoren iz jednog oblika u drugi, ili ponovno interpretiran kao oblik drugog tipa.[6][7] Pretvorba je moguća i nad primitivnim i nad složenim tipovima.

Svaki programski jezik ima vlastita pravila o pretvaranju tipova podataka. Jezici stroge tipizacije rade implicitne pretvorbe u iznimnim slučajevima i ne preporučaju eksplicitne pretvorbe, dok jezici slabe tipizacije izvode mnoge implicitne pretvorbe, što može dovesti do neočekivanih grešaka pri izvođenju.

Implicitna pretvorba uredi

Implicitno pretvaranje tipova kompilator radi automatski (ako su definirana pravila pretvorbe) kako bi izveo pojedine operacije nad podatcima.

Primjerice, kako bi se izračunao izraz 5 + 0.1, kompilator će napraviti implicitnu pretvorbu cijelog broja (integer) 5 u decimalni broj (float) 5.0, zbrojit će dva decimalna broja i vratit će rezultat kao decimalan broj.

U ovakvim izrazima miješanih tipova, vrijednosti jednog ili više pod-tipova mogu pri izvođenju se implicitno pretvoriti u nad-tip kako bi se izvele zatražene operacije.

Sljedeće je ispravan C kod:

double d;
long    l;
int     i;

if (d > i)   d = i;
if (i > l)   l = i;
if (d == l)  d *= 2;

Iako su d, l, i i različiti tipovi podataka, pri svakoj usporedbi ili dodjeli dogodit će se implicitna pretvorba u dva jednaka tipa podatka. Ovo ponašanje može imati neočekivane posljedice i može dovesti do pogrešaka ili gubitka podataka.

  • pretvaranje iz float u int dovodi do zaokruživanja i gubitka decimala
  • pretvaranje iz double u float dovodi do zaokruživanja prema više
  • pretvaranje iz long u int dovodi do gubitka preciznosti
  • neočekivano, pretvaranje iz int u float može dovesti do pogrešaka pri pretvorbi velikih brojeva, što demonstrira sljedeći kod:
#include <stdio.h>

int main(void)
{
    int i_value   = 16777217;
    float f_value = 16777216.0;
    printf("Cijeli broj je: %d\n", i_value);
    printf("Decimalni broj je:   %f\n", f_value);
    printf("Jesu li jednaki?: %d\n", i_value == f_value);
}

Ako se kod izvodi na kompilatoru koji implementira float kao decimalni broj jednostruke preciznosti sukladno IEEE standardu, i procesoru koji promiče cijeli broj na barem 32 bita, gornji će kod vratiti sljedeći neobičan ispis:

Cijeli broj je: 16777217
Decimalni broj je: 16777216.000000
Jesu li jednaki?: 1

U zadnjoj liniji broj 1 predstavlja zaključak "tvrdnja je istinita" (odnosno brojevi su jednaki). Ovo se ponašanje događa jer se cijeli broj implicitno pretvara u decimalni broj jednostruke preciznosti (kako je opisano standardom IEEE 754). Pretvorba uzrokuje gubitak preciznosti (koristi se jednak broj bitova za prikaz cijelog broja, i za prikaz decimalnog broja, pa stoga decimalni broj može prikazati manji raspon vrijednosti jer se dio bitova mora odvojiti za decimale).

Promicanje tipova uredi

Poseban slučaj implicitne pretvorbe tipova je promicanje (unaprjeđenje, promocija) tipova, gdje kompilator automatski proširuje binarni oblik objekata cjelobrojnog ili decimalnog tipa. Promicanjem vrijednost varijable nikad ne gubi preciznost, a sama vrijednost spremljena u memoriji ne mijenja se zbog promocije.

Promicanje se događa ako je zapis tipa podatka manji od najmanjeg tipa koji aritmetičko-logička jedinica računalnog procesora može obraditi. Također se događa prije obrade logičkih (boolean) operacija kao preduvjet njihova izvođenja. Jezici C i C++ implicitno promiču tipove boolean (istina/laž), char (znak), w_char_t (Unikodni UTF-16 znak), enum (enumeracije) i short int (cijeli broj smanjena raspona) u tip int (cijeli broj), i također tip float (decimalni broj jednostruke preciznosti) u double (decimalni broj dvostruke preciznosti).

Eksplicitna pretvorba uredi

Eksplicitnu pretvorbu autor programskog koda mora zatražiti.

double da = 3.3;
double db = 3.3;
double dc = 3.4;
int rezultat = (int)da + (int)db + (int)dc; // rezultat = 9
// da se koristila implicitna konverzija (kod "rezultat = da + db + dc"), rezultat bi bio 10

Postoji nekoliko vrsta eksplicitne pretvorbe.

provjerena (checked)
Prije izvođenja pretvorbe vrši se provjera može li ciljni tip spremiti izvornu vrijednost. Ako ne može, program vraća pogrešku pri izvođenju.
neprovjerena (unchecked)
Ne izvodi se provjera. Ako ciljni tip ne može spremiti vrijednost, rezultat nije definiran (tip podatka je undefined).
uzorak bitova (bit pattern)
Bitovi izvornog podatka u memoriji kopiraju se na mjesto nove varijable. Bitovi se interpretiraju sukladno odredišnom tipu.

Objektno orijentirani jezici podržavaju i radnju suprotnu promociji: referenca bazne klase može se pretvoriti u tip jedne od njenih pod-klasa.

C# i C++ uredi

U jeziku C#, pretvorba tipova može biti sigurna ili nesigurna.[8]

Animal animal = new Cat();

// sigurne pretvorbe:
Bulldog b = (Bulldog) animal;
// ako je animal tipa Bulldog, 
//      onda je tip podatka varijable animal jednaka Bulldog,
//      u suprotnom vrati iznimku

b = animal as Bulldog;
// ako je animal tipa Bulldog, 
//      onda je b = (Bulldog) animal (isto kao iznad)
//      u suprotnom b = null

// nesigurna pretvorba
animal = null;
b = animal as Bulldog;         // b = null

U jeziku C++ sličan se učinak može postići korištenjem operatora dinamičke pretvorbe:

Animal* animal = new Cat;

Bulldog* b = static_cast<Bulldog*>(animal); 
// radi samo kao su klase Animal ili Bulldog derivirane jedna druge,
//       u suprotnom greška pri kompilaciji

b = dynamic_cast<Bulldog*>(animal);
// ako je animal tipa Bulldog vraća b = (Bulldog*) animal,
//       u suprotnom vraća b = null-pointer

Bulldog& br = static_cast<Bulldog&>(*animal); 
// isto kao iznad, ali pri neuspjehu se vraća iznimka NullPointerException

animal = nullptr;
b = dynamic_cast<Bulldog*>(animal);         // b = null-pointer

delete animal;

Izvori uredi

  1. a b c Mehrotra, Dheeraj. 2008. S. Chand's Computer Science. str. 81–83. ISBN 978-8121929844
  2. Programming Languages - Design and Constructs. 2013. str. 35. ISBN 978-9381159415
  3. a b Reilly, Edwin. 2004. Concise Encyclopedia of Computer Science. str. 82, 110. ISBN 0470090952
  4. Fenton, Steve. 2017. Pro TypeScript: Application-Scale JavaScript Development. str. xxiii. ISBN 978-1484232491
  5. PHP: Type Juggling - Manual. php.net. Pristupljeno 27. siječnja 2019.
  6. a b Olsson, Mikael. 2013. C++ Quick Syntax Reference. str. 87–89. ISBN 978-1430262770
  7. Kruse, Rudolf; Borgelt, Christian; Braune, Christian; Mostaghim, Sanaz; Steinbrecher, Matthias. 16. rujna 2016. Computational Intelligence: A Methodological Introduction. str. 269. ISBN 978-1447172963
  8. Mössenböck, Hanspeter. 25. ožujka 2002. Advanced C#: Checked Type Casts (PDF). Institut für Systemsoftware, Johannes Kepler Universität Linz, Fachbereich Informatik. str. 5. Pristupljeno 4. kolovoza 2011. at C# Tutorial