Typkonvertering
Inom datavetenskap är typkonvertering , typgjutning , typtvång och typjonglering olika sätt att ändra ett uttryck från en datatyp till en annan. Ett exempel skulle vara omvandlingen av ett heltalsvärde till ett flyttalsvärde eller dess textrepresentation som en sträng , och vice versa. Typkonverteringar kan dra fördel av vissa funktioner i typhierarkier eller datarepresentationer . Två viktiga aspekter av en typkonvertering är om den sker implicit (automatiskt) eller explicit , och om den underliggande datarepresentationen konverteras från en representation till en annan, eller om en given representation bara omtolkas som representationen av en annan datatyp. I allmänhet kan både primitiva och sammansatta datatyper konverteras.
Varje programmeringsspråk har sina egna regler för hur typer kan konverteras. Språk med stark typning gör vanligtvis lite implicit omvandling och motverkar omtolkning av representationer, medan språk med svag typning utför många implicita omvandlingar mellan datatyper. Svagt skrivspråk tillåter ofta att kompilatorn tvingas att godtyckligt tolka en datapost som att den har olika representationer – detta kan vara ett icke-uppenbart programmeringsfel eller en teknisk metod för att direkt hantera underliggande hårdvara.
används ordet tvång för att beteckna en implicit konvertering, antingen under kompilering eller under körning . Till exempel, i ett uttryck som blandar heltal och flyttal (som 5 + 0,1), kommer kompilatorn automatiskt att omvandla heltalsrepresentation till flyttalsrepresentation så att bråk inte går förlorade. Explicita typkonverteringar indikeras antingen genom att skriva ytterligare kod (t.ex. lägga till typidentifierare eller anropa inbyggda rutiner ) eller genom att koda omvandlingsrutiner för kompilatorn att använda när den annars skulle stanna med en typfel.
I de flesta ALGOL- liknande språk, som Pascal , Modula-2 , Ada och Delphi , är konvertering och gjutning helt olika begrepp. I dessa språk konvertering till att antingen implicit eller explicit ändra ett värde från en datatypslagringsformat till ett annat, t.ex. ett 16-bitars heltal till ett 32-bitars heltal. Lagringsbehoven kan ändras som ett resultat av konverteringen, inklusive en eventuell förlust av precision eller trunkering. Ordet cast , å andra sidan, syftar på att explicit ändra tolkningen av bitmönstret som representerar ett värde från en typ till en annan. Till exempel kan 32 sammanhängande bitar behandlas som en array med 32 booleaner, en 4-byte-sträng, ett osignerat 32-bitars heltal eller ett IEEE-flyttalsvärde med enkel precision. Eftersom de lagrade bitarna aldrig ändras måste programmeraren känna till detaljer på låg nivå såsom representationsformat, byteordning och anpassningsbehov, för att kasta meningsfullt.
I språkfamiljen C och ALGOL 68 hänvisar ordet cast vanligtvis till en explicit typkonvertering (i motsats till en implicit konvertering), vilket orsakar en viss tvetydighet om huruvida detta är en omtolkning av ett bitmönster eller en verklig datarepresentation omvandling. Viktigare är de många sätt och regler som gäller för vilken datatyp (eller klass) som finns av en pekare och hur en pekare kan justeras av kompilatorn i fall som objekt (klass) arv.
Explicit casting på olika språk
Ada
Ada tillhandahåller en generisk biblioteksfunktion Unchecked_Conversion.
C-liknande språk
Implicit typkonvertering
Implicit typkonvertering, även känd som tvång eller typjonglering , är en automatisk typkonvertering av kompilatorn . Vissa programmeringsspråk tillåter kompilatorer att tillhandahålla tvång; andra kräver det.
kan data av en eller flera undertyper konverteras till en supertyp efter behov under körning så att programmet körs korrekt. Till exempel är följande juridiska C-språkkod :
dubbel d ; lång l ; int i ; if ( d > i ) d = i ; om ( i > l ) l = i ; om ( d == 1 ) d *= 2 ;
Även om d , l och i tillhör olika datatyper, kommer de automatiskt att omvandlas till lika datatyper varje gång en jämförelse eller tilldelning utförs. Detta beteende bör användas med försiktighet, eftersom oavsiktliga konsekvenser kan uppstå. Data kan gå förlorade vid omvandling av representationer från flyttal till heltal, eftersom de bråkdelar av flyttalsvärdena kommer att trunkeras (avrundas mot noll). Omvänt kan precision gå förlorad vid omvandling av representationer från heltal till flyttal, eftersom en flyttalstyp kanske inte kan representera alla möjliga värden av någon heltalstyp exakt. Till exempel float
vara en IEEE 754 enkelprecisionstyp, som inte kan representera heltal 16777217 exakt, medan en 32-bitars heltalstyp kan. Detta kan leda till ointuitivt beteende, vilket visas av följande kod:
#include <stdio.h> int main ( void ) { int i_value = 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 ); }
På kompilatorer som implementerar flöten som IEEE enkel precision, och ints som minst 32 bitar, kommer den här koden att ge denna märkliga utskrift:
Heltalet är: 16777217 Flottören är: 16777216.000000 Deras likhet: 1
Observera att 1 representerar jämlikhet på sista raden ovan. Detta udda beteende orsakas av en implicit omvandling av i_value
till float när den jämförs med f_value
. Omvandlingen orsakar förlust av precision, vilket gör värdena lika före jämförelsen.
Viktiga takeaways:
-
float
toint
orsakar trunkering , dvs. avlägsnande av fraktionsdelen. -
dubbla
tillflytande
orsakar avrundning av siffran. -
long
toint
orsakar att överflödiga bitar av högre ordning tappas.
Typ kampanj
Ett specialfall av implicit typkonvertering är typbefordran, där ett objekt automatiskt konverteras till en annan datatyp som representerar en superuppsättning av den ursprungliga typen. Kampanjer används vanligtvis med typer som är mindre än den ursprungliga typen av målplattformens aritmetiska logiska enhet (ALU), före aritmetiska och logiska operationer, för att göra sådana operationer möjliga, eller mer effektiva om ALU kan arbeta med mer än en typ. C och C++ utför sådan befordran för objekt av boolesk, karaktär, bred karaktär, uppräkning och korta heltalstyper som befordras till int, och för objekt av typen float, som befordras till dubbel. Till skillnad från vissa andra typer av konverteringar, förlorar kampanjer aldrig precision eller ändrar värdet som lagras i objektet.
I Java :
int x = 3 ; dubbel y = 3,5 ; System . ut . println ( x + y ); // Utdata blir 6.5
Explicit typkonvertering
Explicit typkonvertering, även kallad typcasting, är en typkonvertering som är uttryckligen definierad inom ett program (istället för att göras automatiskt enligt språkets regler för implicit typkonvertering). Det begärs av användaren i programmet.
dubbel da = 3,3 ; dubbel db = 3,3 ; dubbel st = 3,4 ; int resultat = ( int ) da + ( int ) db + ( int ) dc ; // resultat == 9 // om implicit konvertering skulle användas (som med "result = da + db + dc"), skulle resultatet vara lika med 10
Det finns flera typer av explicit konvertering.
- checked
- Innan konverteringen utförs görs en körtidskontroll för att se om destinationstypen kan hålla källvärdet. Om inte, uppstår ett feltillstånd.
- avmarkerad
- Ingen kontroll utförs. Om destinationstypen inte kan innehålla källvärdet är resultatet odefinierat.
- bitmönster
- Den råa bitrepresentationen av källan kopieras ordagrant, och den omtolkas enligt destinationstypen. Detta kan också uppnås via aliasing .
I objektorienterade programmeringsspråk kan objekt också nedkastas : en referens för en basklass castas till en av dess härledda klasser.
C# och C++
I C# kan typkonvertering göras på ett säkert eller osäkert (dvs. C-liknande) sätt, det förra kallas checked type cast .
Djurdjur = ny katt () ; Bulldog b = ( Bulldog ) djur ; // if (djur är Bulldog), stat.type(animal) är Bulldog, annars ett undantag b = djur som Bulldog ; // if (djur är Bulldog), b = (Bulldog) djur, annars b = null djur = null ; b = djur som Bulldog ; // b == null
I C++ kan en liknande effekt uppnås med C++-stil cast-syntax .
Djur * djur = ny katt ; Bulldog * b = static_cast < Bulldog *> ( djur ); // kompilerar endast om antingen Animal eller Bulldog härrör från den andra (eller samma) b = dynamic_cast < Bulldog *> ( animal ); // if (djur är Bulldog), b = (Bulldog*) djur, annars b = nullptr Bulldog & br = static_cast < Bulldog &> ( * animal ); // samma som ovan, men ett undantag kommer att kastas om en nullptr skulle returneras // detta syns inte i kod där undantagshantering undviks animal = nullptr ; b = dynamic_cast < Bulldog *> ( djur ); // b == nullptr radera djur ; // alltid gratis resurser
Eiffel
I Eiffel är begreppet typkonvertering integrerat i typsystemets regler. Tilldelningsregeln säger att en uppgift, till exempel:
x := y
är giltigt om och endast om typen av dess källuttryck, y
i detta fall, är kompatibel med typen av dess målenhet, x
i detta fall. I den här regeln kompatibel med att typen av källuttryck antingen överensstämmer med eller konverterar till målets. Typöverensstämmelse definieras av de välbekanta reglerna för polymorfism i objektorienterad programmering . Till exempel, i uppgiften ovan, överensstämmer typen av y
med typen av x
om klassen som y
är baserad på är en ättling till den som x
är baserad på.
Definition av typkonvertering i Eiffel
Åtgärderna för typkonvertering i Eiffel, specifikt konverterar till och konverterar från, definieras som:
En typ baserad på en klass CU konverterar till en typ T baserad på en klass CT (och T konverterar från U) om antingen
- CT har en konverteringsprocedur som använder U som en konverteringstyp, eller
- CU har en konverteringsfråga som listar T som en konverteringstyp
Exempel
Eiffel är ett helt kompatibelt språk för Microsoft .NET Framework . Innan utvecklingen av .NET hade Eiffel redan omfattande klassbibliotek. Att använda .NET-typbiblioteken, särskilt med vanliga typer som strängar, utgör ett konverteringsproblem. Befintlig Eiffel-mjukvara använder strängklasserna (som STRING_8
) från Eiffel-biblioteken, men Eiffel-programvara skriven för .NET måste använda .NET-strängklassen ( System.String
) i många fall, till exempel när man anropar .NET-metoder som förväntar sig objekt av typen .NET som ska skickas som argument. Så omvandlingen av dessa typer fram och tillbaka måste vara så smidig som möjligt.
my_string : STRING_8 -- Native Eiffel string my_system_string : SYSTEM_STRING -- Native .NET string ... my_string := my_system_string
I koden ovan deklareras två strängar, en av varje typ ( SYSTEM_STRING
är det Eiffelkompatibla aliaset för System.String). Eftersom System.String
inte överensstämmer med STRING_8
, är tilldelningen ovan endast giltig om System.String
konverterar till STRING_8
.
Eiffelklassen STRING_8
har en konverteringsprocedur make_from_cil
för objekt av typen System.String
. Konverteringsprocedurer är också alltid betecknade som skapande procedurer (liknande konstruktörer). Följande är ett utdrag från STRING_8
:
klass STRING_8 ... skapa make_from_cil ... konvertera make_from_cil ({ SYSTEM_STRING } ) ...
Närvaron av konverteringsproceduren gör uppdraget:
min_sträng := mitt_system_sträng
semantiskt ekvivalent med:
skapa min_sträng . make_from_cil ( my_system_string )
där min_sträng
är konstruerad som ett nytt objekt av typen STRING_8
med innehåll motsvarande det i mitt_system_sträng
.
Så här hanterar du en uppgift med originalkälla och mål omvänt:
my_system_string := min_sträng
klassen STRING_8
innehåller också en konverteringsfråga to_cil
som kommer att producera en System.String
från en instans av STRING_8
.
klass STRING_8 ... skapa make_from_cil ... konvertera make_from_cil ({ SYSTEM_STRING }) till_cil : { SYSTEM_STRING } ...
Uppgiften:
my_system_string := min_sträng
blir då likvärdig med:
mitt_system_sträng := min_sträng . to_cil
I Eiffel är inställningen för typkonvertering inkluderad i klasskoden, men tycks sedan ske lika automatiskt som explicit typkonvertering i klientkoden. Det inkluderar inte bara tilldelningar utan även andra typer av bilagor, såsom argument (parameter) substitution.
Rost
Rost ger ingen implicit typomvandling (tvång) mellan primitiva typer. Men explicit typkonvertering (casting) kan utföras med nyckelordet as .
println! ( "1000 som en u16 är: {}" , 1000 som u16 );
Implicit casting med otaggade fackföreningar
Många programmeringsspråk stöder fackföreningstyper som kan ha ett värde av flera typer. Otaggade fackföreningar tillhandahålls på vissa språk med lös typkontroll, som C och PL/I , men även i originalet Pascal . Dessa kan användas för att tolka bitmönstret för en typ som ett värde av en annan typ.
Säkerhetsproblem
I hacking är typecasting missbruk av typkonvertering för att tillfälligt ändra en variabels datatyp från hur den ursprungligen definierades. Detta ger möjligheter för hackare eftersom vid typkonvertering efter att en variabel "typecasts" för att bli en annan datatyp, kommer kompilatorn att behandla den hackade variabeln som den nya datatypen för den specifika operationen.
Se även
externa länkar
- Casting i Ada
- Casta i C++
- C++ Referensguide Varför jag hatar C++ Cast Operators, av Danny Kalev
- Casting i Java
- Implicita omvandlingar i C#
- Implicit Type Casting på Cppreference.com
- Statiska och omtolkningsgjutningar i C++
- Upp- och nedsändning i F#