Tyyppimuunnos ( typecasting , pakottaminen ) - tietojenkäsittelytieteessä yhden tyypin arvon muuntaminen toisen tyypin arvoksi .
On olemassa tyyppejä:
Ohjelmoija määrittelee eksplisiittisen näyttelijän ohjelman tekstissä käyttämällä:
Kääntäjä ( kääntäjä tai tulkki ) suorittaa implisiittisen näyttelemisen kielistandardissa kuvattujen sääntöjen mukaisesti. Useimmat kielistandardit kieltävät implisiittiset muunnokset.
Heikosti kirjoitetuissa oliopohjaisissa kielissä, kuten C++ , periytymismekanismi toteutetaan heittämällä nykyisen objektin osoittimen tyyppi perusluokkaan ( tyyppiturvallisissa kielissä , kuten OCaml , tyypin valun käsite pohjimmiltaan puuttuu, ja alatyyppikomponenttiin viittaamisen hyväksyttävyyttä valvovat johdonmukaisuuden tarkistusmekanismityypit käännöshetkellä, ja suora pääsy säilyy konekoodissa).
Implisiittinen tyyppivalu tapahtuu seuraavissa tapauksissa [1] :
Esimerkiksi suoritettaessa binääriaritmeettista operaatiota operandien arvot heitetään samaan tyyppiin. Periytymisessä johdetut luokkaosoittimet heitetään perusluokan osoittimiin.
Harkitse esimerkkiä C -kielellä .
kaksinkertainen d ; // todellinen tyyppi pitkä l ; // kokonaislukutyyppi int i ; // kokonaislukutyyppi jos ( d > i ) d = i ; jos ( i > l ) l = i ; jos ( d = = l ) d * = 2 ;Vertailuoperaatioita ja osoitusta tehtäessä erityyppisiä muuttujia implisiittisesti valetaan samaan tyyppiin.
Implisiittisillä muunnoksilla voi olla sivuvaikutuksia. Esimerkiksi heitettäessä reaalityyppistä lukua kokonaislukutyyppiin murto-osa leikataan pois ( pyöristystä ei suoriteta) [2] . Käänteinen muunnos voi heikentää tarkkuutta reaali- ja kokonaislukujen esittämisen erojen vuoksi . Esimerkiksi tyyppimuuttujaan ( IEEE 754 yhden tarkkuuden liukulukuluku ) et voi tallentaa lukua 16 777 217 ilman tarkkuuden menetystä, mutta voit tallentaa 32-bittiseen kokonaislukutyyppiseen muuttujaan. Tarkkuuden menettämisen vuoksi saman luvun vertailuoperaatiot, joita edustavat kokonaisluku- ja reaalityypit (esimerkiksi ja ), voivat antaa vääriä tuloksia (luvut eivät välttämättä ole yhtä suuria). float intintfloat
#include <stdio.h> int main ( tyhjä ) { int i_arvo = 16777217 ; kelluva f_arvo = 16777216.0 ; printf ( "Kokonaisluku on:%d \n " , i_arvo ); printf ( "Float on: %f \n " , f_arvo ); printf ( "Niiden yhtäläisyys:%d \n " , i_arvo == f_arvo ); }Yllä oleva koodi tulostaa seuraavan, jos koko on 32 bittiä ja kääntäjä tukee IEEE 754 -standardia : int
Kokonaisluku on: 16777217 Kellunta on: 16777216.000000 Heidän tasa-arvonsa: 1Eksplisiittisessä tyyppisuorituksessa tyypin nimi määritetään suluissa ennen muuttujaa tai lauseketta. Harkitse esimerkkiä.
int X ; int Y = 200 ; char C = 30 ; X = ( int ) C * 10 + Y ; // C-muuttuja heitetään tyyppiin intViimeisen lausekkeen arvioimiseksi kääntäjä tekee jotain näin:
Siitä huolimatta virheet ovat mahdollisia. Tyyppi voi olla joko allekirjoitettu ( ) tai allekirjoittamaton ( ); tulos riippuu kääntäjän toteutuksesta ja standardi sallii tämän käyttäytymisen. Ellejettömän tyypin arvo, kun se muunnetaan etumerkityksi tyypiksi, voi osoittautua negatiiviseksi, koska joissakin prosessoreissa on toteutettu konekäskyjä . Epäselvyyksien välttämiseksi on suositeltavaa määrittää nimenomaisesti tyypin allekirjoitus . charsigned charunsigned charcharintchar
C++ : ssa on viisi eksplisiittistä tyyppimuunnosoperaattoria. Ensimmäistä toimintoa, sulkuja ( ), tuetaan yhteensopivuuden säilyttämiseksi C :n kanssa . Loput neljä operaatiota kirjoitetaan muodossa (type_to)expression_from
xxx_cast < type_to >( lauseke_from )Harkitse esimerkkiä.
y = static_cast < signed short > ( 65534 ); // muuttuja y asetetaan arvoon -2Hankalat avainsanat muistuttavat ohjelmoijaa siitä, että tyyppivalu on täynnä ongelmia.
Operaatio static_castTarkoitus: Kelvollisia heittoja.
Toiminto on samanlainen kuin sulkuoperaatio yhdellä poikkeuksella: se ei anna osoittimia toisiinsa liittymättömiin tyyppeihin (toimintoa käytetään tähän ). static_castreinterpret_cast
Sovellus:
Rajoitukset expression_from: ei.
Rajoitukset type_to: Lausekkeen arvo on voitava muuntaa expression_fromtyypiksi type_to, käyttäen operator type_totai konstruktoriksi.
Tuottaako operaatio koodia: Yleensä kyllä (esimerkiksi ylikuormitetun cast- tai konstruktorioperaation kutsuminen). static_cast
Loogisten virheiden lähteet: riippuu siitä, mitä aiot tehdä toiminnolla. Ylivuodot, alueen ulkopuolella ja jopa (osoittimen muunnoksia varten) muistin vioittumiset ovat mahdollisia.
Esimerkkejä.
// Hanki osumaprosentti. kaksinkertainen ( _ const int aHitCount , // osumien määrä const int aShotCount // laukausten määrä ) { if ( aShotCount == 0 ) palauttaa 0.0 ; // Casting tuplaan suoritetaan todellisen (ei-kokonaisluvun) jaon palauttamiseksi static_cast < double > ( aHitCount * 100 ) / static_cast < double > ( aShotCount ); } // seuraavat rivit ovat vastaavia // käyttämällä static_cast-toimintoa merkkijono s = static_cast < string > ( "Hei!" ); // kutsu konstruktoria yhdellä argumentilla merkkijono s = string ( "Hei!" ); // suluilla toimintamerkkijono s = ( merkkijono ) " Hei!" ; merkkijono s = static_cast < merkkijono > ( 5 ); // ei käännä, kääntäjä ei löydä sopivaa rakentajaa Operaatio dynamic_castTarkoitus: perintöhierarkian purkaminen erityisellä käyttäytymisellä, jos objekti ei ole haluttua tyyppiä.
Toiminto saa tietoa objektin tyypistä RTTIexpression_from :n avulla . Jos tyyppi on tai sen alatyyppi, heitto suoritetaan. Muuten: type_to
Rajoitukset expression_from: Lausekkeen on oltava viittaus tai osoitin objektiin, jolla on vähintään yksi virtuaalinen funktio .
Rajoitukset type_to: viittaus tai osoitin expression_fromtyypin lapsiin.
Luoko operaatio koodin: kyllä. dynamic_cast
Loogiset virheet ovat mahdollisia, jos operaatio läpäisee argumentin, jolla ei ole tyyppiä type_toeikä tarkista osoittimen tasa-arvoa (vastaavasti älä käsittele poikkeusta ). NULLstd::bad_cast
Operaatio const_castTarkoitus: modifioijien poistaminen/asennus ja /tai . Usein tätä käytetään ohjelman tai kirjaston huonon arkkitehtuurin kiertämiseen, C:n kiinnittämiseen C++:aan, tiedon välittämiseen yleisten osoittimien kautta , funktion const- ja non-const-versioiden kirjoittamiseen samanaikaisesti [3] ( on olemassa ohitus C++14 [3] ). constvolatilemutablevoid*decltype(auto)
Rajoitukset expression_from: Lausekkeen on palautettava viite tai osoitin.
Rajoitukset type_to: tyypin type_toon vastattava lausekkeen tyyppiä muuntimeen ( muuttujiin expression_from) ja .constvolatilemutable
Luoko operaatio koodin: no. const_cast
Loogisten virheiden lähteet: Ohjelma voi muokata muuttumatonta objektia. Joskus tämä voi johtaa segmentointivirheeseen , joskus alirutiini ei voi odottaa [3] , että sen luettavaksi asetettu muisti on yhtäkkiä muuttunut.
Harkitse esimerkiksi dynaamisen kirjaston koodia .
#include <merkkijono> // merkkijono käyttäen nimiavaruutta std ; nimiavaruus { string s = "Wikipedia" ; // Yleinen muuttuja // Metodimerkkijono::c_str() palauttaa osoittimen, jonka tyyppi on const char * } typedef char * PChar ; void __declspec ( dllexport ) WINAPI SomeDllFunction ( PChar & rMessage ) { // muuntaa char const * merkiksi * rMessage = const_cast < char * > ( s . c_str () ); }Kun kirjasto ladataan prosessimuistiin , se luo uuden datasegmentin, joka sisältää globaaleja muuttujia. Funktiokoodi sijaitsee kirjastossa ja palauttaa kutsuttaessa osoittimen globaalin luokkaobjektin piilotettuun jäseneen . Toimintoa käytetään muuntimen poistamiseen . SomeDllFunction()stringconst_castconst
Operaatio reinterpret_castTehtävä: Kirjoitus sanaleikki - Eri tyypin (ei välttämättä yhteensopiva annetun) määrittäminen muistipaikkaan säilyttäen samalla bittiesitys.
Lausekkeen palauttamaa expression_fromobjektia käsitellään tyypin objektina type_to.
Rajoitukset expression_from: Lausekkeen on palautettava järjestystyyppinen arvo (mikä tahansa kokonaisluku, looginen arvo tai enum ), osoitin tai viittaus. boolenum
Rajoitukset type_to:
Luoko operaatio koodin: no. reinterpret_cast
Loogisten virheiden lähteet. Lausekkeen palauttama objekti expression_fromei ehkä ole tyyppiä type_to. Tätä ei voi mitenkään tarkistaa, ohjelmoija ottaa täyden vastuun muunnoksen oikeellisuudesta.
Harkitse esimerkkejä.
// Palauttaa tosi, jos x on äärellinen. // Palauttaa epätosi, jos luku x on ∞ tai NaN. bool isfinite ( double const x ) { // muunnos double const -> uint64_t const & uint64_t const & y = reinterpret_cast < uint64_t const & > ( x ); paluu ( ( y & UINT64_C ( 0x7FF0000000000000 ) ) != UINT64_C ( 0x7FF0000000000000 ) ); } // yritä saada tilapäisen arvon osoite long const & y = reinterpret_cast < long const & > ( x + 5.0 ); // virhe: lauseke x + 5.0 ei ole viite