Typomvandling ( typcasting , tvång ) - inom datavetenskap , konvertering av ett värde av en typ till ett värde av en annan typ .
Det finns typavgjutningar:
Explicit rollbesättning anges av programmeraren i programtexten med hjälp av:
En implicit cast utförs av en översättare ( kompilator eller tolk ) enligt reglerna som beskrivs i språkstandarden. De flesta språkstandarder förbjuder implicita omvandlingar.
I svagt typade objektorienterade språk som C++ implementeras arvsmekanismen genom att casta pekarens typ till det aktuella objektet till basklassen (i typsäkra språk som OCaml , begreppet typcasting är i grunden frånvarande, och tillåtligheten av att hänvisa till undertypskomponenten styrs av mekanismtyperna för konsistenskontroll vid kompilering, och direktåtkomst kvarstår i maskinkoden).
Implicit typgjutning förekommer i följande fall [1] :
Till exempel, när du utför en binär aritmetisk operation, casts värdena på operanderna till samma typ. I arv, härledda klasspekare gjuts till basklasspekare.
Tänk på ett exempel på C- språk .
dubbel d ; // riktig typ lång l ; // heltalstyp int i ; // heltalstyp if ( d > i ) d = i ; om ( i > l ) l = i ; om ( d == 1 ) d *= 2 ;När man utför jämförelseoperationer och vid tilldelning, gjuts variabler av olika typer implicit till samma typ.
Implicita konverteringar kan ha biverkningar. Till exempel, när man gjuter ett antal verkliga typer till en heltalstyp, skärs bråkdelen av ( avrundning utförs inte) [2] . Den omvända omvandlingen kan minska noggrannheten på grund av skillnader i representationen av reella tal och heltal. Till exempel, i en typvariabel ( IEEE 754 single-precision flyttalnummer ), kan du inte lagra talet 16 777 217 utan förlust av precision, men du kan i en 32-bitars heltalsvariabel. På grund av förlusten av precision kan jämförelseoperationer av samma tal representerade av heltal och reella typer (till exempel och ) ge falska resultat (tal kanske inte är lika). float intintfloat
#include <stdio.h> int main ( void ) { int i_värde = 16777217 ; float f_value = 16777216,0 ; printf ( "Heltalet är:%d \n " , i_värde ); printf ( "Flytet är: %f \n " , f_värde ); printf ( "Deras likhet:%d \n " , i_value == f_value ); }Ovanstående kod matar ut följande om storleken är 32 bitar och kompilatorn stöder IEEE 754- standarden : int
Heltalet är: 16777217 Flottören är: 16777216.000000 Deras jämlikhet: 1För explicit typcasting anges typnamnet inom parentes före variabeln eller uttrycket. Tänk på ett exempel.
int X ; int Y = 200 ; kol C = 30 ; X = ( int ) C * 10 + Y ; // C-variabel cast till typ intFör att utvärdera det sista uttrycket gör kompilatorn ungefär så här:
Trots det är misstag möjliga. Typen kan antingen vara signerad ( ) eller osignerad ( ); resultatet beror på kompilatorns implementering och detta beteende tillåts av standarden. Värdet på en osignerad typ när den konverteras till en signerad typ kan visa sig vara negativt på grund av implementeringen av maskininstruktioner på vissa processorer . För att undvika oklarheter rekommenderas det att uttryckligen ange signering för typ . charsigned charunsigned charcharintchar
Det finns fem explicita typkonverteringsoperatorer i C++ . Den första operationen, parenteser ( ), stöds för att bibehålla kompatibilitet med C . De återstående fyra operationerna skrivs som (type_to)expression_from
xxx_cast < typ_to >( expression_from )Tänk på ett exempel.
y = static_cast < signerad kort > ( 65534 ); // variabeln y sätts till -2Besvärliga nyckelord är en påminnelse till programmeraren om att typgjutning är full av problem.
Operation static_castSyfte: Giltiga avgjutningar.
Operationen liknar parentesoperationen med ett undantag: den skickar inte pekare till orelaterade typer (operationen används för detta ). static_castreinterpret_cast
Ansökan:
Begränsningar på expression_from: nej.
Restriktioner på type_to: Det måste finnas ett sätt att konvertera uttryckets värde expression_fromtill typ type_to, med hjälp av operator type_toeller konstruktor.
Ger operationen kod: Generellt ja (till exempel anropar en överbelastad cast- eller konstruktoroperation). static_cast
Källor till logiska fel: beror på vad du ska göra med operationen. Översvämningar, utom räckvidd och till och med (för pekarkonverteringar) minneskorruption är möjliga.
Exempel.
// Få träffprocent. dubbel -tippercent ( const int aHitCount , // antal träffar konstant int aShotCount // antal skott ) { if ( aShotCount == 0 ) returnera 0,0 ; // Casting till dubbel görs för att utföra reell (icke-heltals) division return static_cast < double > ( aHitCount * 100 ) / static_cast < double > ( aShotCount ); } // följande rader är likvärdiga // använder operationssträngen static_cast s = static_cast < string > ( " Hej!" ); // anrop konstruktor med ett argument sträng s = sträng ( "Hej!" ); // med parentesens operation string s = ( string ) "Hej!" ; sträng s = static_cast < sträng > ( 5 ); // kompilerar inte, kompilatorn kan inte hitta en lämplig konstruktor Operation dynamic_castSyfte: kasta ner arvshierarkin, med speciellt beteende om objektet inte är av önskad typ.
Operationen erhåller information om typen av objekt expression_frommed hjälp av RTTI . Om typen är type_toeller en undertyp av den, utförs casten. Annat:
Restriktioner på expression_from: Uttrycket måste vara en referens eller pekare till ett objekt som har minst en virtuell funktion .
Begränsningar på type_to: en referens eller pekare till ett underordnat av en expression_fromtyp.
Genererar operationen en kod: ja. dynamic_cast
Logiska fel är möjliga om operationen skickar ett argument som inte har typ type_tooch inte kontrollerar pekaren för likhet (respektive hantera inte undantaget ). NULLstd::bad_cast
Operation const_castSyfte: borttagning/installation av modifierare och /eller . Ofta används detta för att komma runt den dåliga arkitekturen hos ett program eller bibliotek, för att docka C med C++, för att skicka information genom generiska pekare , för att samtidigt skriva en const- och icke-const-version av en funktion [3] ( det finns en bypass i C++14 [3] ). constvolatilemutablevoid*decltype(auto)
Restriktioner för expression_from: Uttrycket måste returnera en referens eller en pekare.
Begränsningar på type_to: typen type_tomåste matcha typen av uttrycket expression_fromupp till modifierare , och . constvolatilemutable
Genererar operationen en kod: nej. const_cast
Källor till logiska fel: Ett program kan modifiera ett oföränderligt objekt. Ibland kan detta leda till ett segmenteringsfel , ibland kan en subrutin inte förvänta sig [3] att minnet som den har gjort tillgängligt för läsning plötsligt har förändrats.
Tänk till exempel på koden för det dynamiska biblioteket .
#inkludera <sträng> // sträng använder namnutrymme std ; namnutrymme { string s = "Wikipedia" ; // Global variabel // method string::c_str() returnerar en pekare av typen const char * } typedef char * PChar ; void __declspec ( dllexport ) WINAPI SomeDllFunction ( PChar & rMessage ) { // konvertera char const * till char * rMessage = const_cast < char * > ( s . c_str () ); }När ett bibliotek läses in i processminnet skapar det ett nytt datasegment som innehåller globala variabler. Funktionskoden finns i biblioteket och, när den anropas, returnerar den en pekare till en dold medlem av det globala klassobjektet . Operationen används för att ta bort modifieraren . SomeDllFunction()stringconst_castconst
Operation reinterpret_castTilldelning: Skriva ordlek - Tilldela en annan typ (inte nödvändigtvis kompatibel med den givna) till en minnesplats samtidigt som bitrepresentationen bevaras.
Objektet som returneras av uttrycket expression_frombehandlas som ett objekt av typen type_to.
Restriktioner på expression_from: Uttrycket måste returnera ett värde av en ordningstyp (valfritt heltal, boolean eller enum ), en pekare eller en referens. boolenum
Begränsningar på type_to:
Genererar operationen en kod: nej. reinterpret_cast
Källor till logiska fel. Objektet som returneras av uttrycket expression_fromkanske inte är av typen type_to. Det finns inget sätt att kontrollera detta, programmeraren tar fullt ansvar för att konverteringen är korrekt.
Tänk på exempel.
// Returnerar sant om x är ändligt. // Returnerar falskt om nummer x är ∞ eller NaN. bool isfinite ( dubbelkonst x ) _ { // conversion double const -> uint64_t const & uint64_t const & y = reinterpret_cast < uint64_t const & > ( x ); return ( ( y & UINT64_C ( 0x7FF00000000000000 ) ) != UINT64_C ( 0x7FF0000000000000 ) ); } // försök att få adressen till ett temporärt värde long const & y = reinterpret_cast < long const & > ( x + 5.0 ); // fel: uttryck x + 5.0 är inte en referens