Převod typů - Type conversion
Ve vědě o počítačích , konverze typu , typ lití , typ nátlaku a typu žonglování různé způsoby provedení změny výrazu z jednoho datového typu na jiný. Příkladem může být převod celočíselné hodnoty na hodnotu s plovoucí desetinnou čárkou nebo její textová reprezentace jako řetězec a naopak. Převody typů mohou využívat výhod určitých funkcí hierarchií typů nebo datových reprezentací . Dva důležité aspekty převodu typu jsou, zda k tomu dochází implicitně (automaticky) nebo explicitně , a zda je podkladová datová reprezentace převedena z jedné reprezentace do druhé, nebo je daná reprezentace pouze reinterpretována jako reprezentace jiného datového typu. Obecně lze převést primitivní i složené datové typy .
Každý programovací jazyk má svá vlastní pravidla, jak lze typy převádět. Jazyky se silným typováním obvykle málo implicitně převádějí a odrazují od reinterpretace reprezentací, zatímco jazyky se slabým typováním provádějí mnoho implicitních převodů mezi datovými typy. Slabý jazyk psaní často umožňuje vynutit kompilátoru, aby libovolně interpretoval datovou položku jako jinou reprezentaci-může to být nejasná chyba programování nebo technická metoda pro přímé řešení základního hardwaru.
Ve většině jazyků se slovo nátlak používá k označení implicitní konverze, buď během kompilace, nebo během běhu . Například ve výrazu mísícím celá čísla a čísla s plovoucí desetinnou čárkou (jako 5 + 0,1) kompilátor automaticky převede celočíselnou reprezentaci na reprezentaci s pohyblivou řádovou čárkou, aby se neztratily zlomky. Konverze explicitního typu jsou indikovány buď zapsáním dalšího kódu (např. Přidáním identifikátorů typů nebo voláním vestavěných rutin ), nebo kódováním rutin převodu, které má kompilátor použít, když by se jinak zastavil s neshodou typů.
Ve většině jazyků podobných ALGOL , jako jsou Pascal , Modula -2 , Ada a Delphi , jsou převody a castingy výrazně odlišné pojmy. V těchto jazycích převod znamená buď implicitně, nebo explicitně změnu hodnoty z jednoho formátu úložiště datového typu na jiný, např. 16bitové celé číslo na 32bitové celé číslo. Potřeby úložiště se mohou v důsledku převodu změnit, včetně možné ztráty přesnosti nebo zkrácení. Slovo obsazení , na druhé straně, se týká výslovně změně výkladu tohoto bitového vzoru , představující hodnotu z jednoho typu do druhého. Například 32 souvislých bitů může být považováno za pole 32 booleů, 4bajtový řetězec, 32bitové celé číslo bez znaménka nebo hodnotu s plovoucí desetinnou čárkou s jednoduchou přesností IEEE. Protože uložené bity nejsou nikdy měněny, musí programátor znát detaily na nízké úrovni, jako je formát reprezentace, pořadí bajtů a potřeby zarovnání, aby bylo možné smysluplně přetypovat.
V rodině jazyků C a ALGOL 68 se slovo cast obvykle vztahuje k převodu explicitního typu (na rozdíl od implicitního převodu), což způsobuje určité nejasnosti ohledně toho, zda se jedná o opětovnou interpretaci bitového vzoru nebo o reprezentaci skutečných dat konverze. Důležitější je množství způsobů a pravidel, která platí pro to, jaký datový typ (nebo třídu) nachází ukazatel a jak může ukazatel upravit kompilátor v případech, jako je dědičnost objektu (třídy).
Porovnání jazyků
Jazyky podobné C
Implicitní převod typů
Implicitní typová konverze, známá také jako nátlak , je automatická konverze typu kompilátorem . Některé programovací jazyky umožňují kompilátorům poskytovat nátlak; ostatní to vyžadují.
Ve výrazu smíšený typ, data jednoho nebo více subtypů mohou být převedeny na supertypu podle potřeby při běhu , takže program bude fungovat správně. Například následující je zákonný kód jazyka C :
double d;
long l;
int i;
if (d > i) d = i;
if (i > l) l = i;
if (d == l) d *= 2;
Ačkoli d , l a i patří k různým datovým typům, budou automaticky převedeny na stejné datové typy při každém provedení porovnání nebo přiřazení. Toto chování by mělo být používáno opatrně, protože mohou nastat nechtěné důsledky . Data lze ztratit při převodu reprezentací z plovoucí desetinné čárky na celé číslo, protože zlomkové složky hodnot s plovoucí desetinnou čárkou budou zkráceny (zaokrouhleny směrem k nule). Přesnost naopak může být ztracena při převodu reprezentací z celého čísla na plovoucí desetinnou čárku, protože typ s plovoucí desetinnou čárkou nemusí být schopen přesně reprezentovat celočíselný typ. Může float
to být například typ s jednoduchou přesností IEEE 754 , který nemůže přesně reprezentovat celé číslo 16777217, zatímco typ 32bitového celého čísla může. To může vést k neintuitivnímu chování, jak ukazuje následující kód:
#include <stdio.h>
int main(void)
{
int i_value = 16777217;
float f_value = 16777216.0;
printf("The integer is: %d\n", i_value);
printf("The float is: %f\n", f_value);
printf("Their equality: %d\n", i_value == f_value);
}
Na kompilátorech, které implementují floaty s jednoduchou přesností IEEE, a ints jako alespoň 32 bitů, tento kód poskytne tento zvláštní výtisk:
The integer is: 16777217 The float is: 16777216.000000 Their equality: 1
Všimněte si, že 1 představuje rovnost v posledním řádku výše. Toto zvláštní chování je způsobeno implicitní konverzí i_value
na float, když je porovnáno s f_value
. Převod způsobí ztrátu přesnosti, což činí hodnoty před porovnáním stejné.
Důležité informace:
-
float
naint
příčinách zkrácení , tj odstranění nepatrné části. -
double
kfloat
příčinám zaokrouhlování číslice. -
long
naint
příčiny klesá přebytečných vyšších řádů bitů.
Propagace typu
Zvláštním případem převodu implicitních typů je propagace typu, kde kompilátor automaticky rozšiřuje binární reprezentaci objektů celočíselných typů nebo typů s plovoucí desetinnou čárkou. Propagace se běžně používají s typy menšími než nativní typ aritmetické logické jednotky (ALU) cílové platformy , před aritmetickými a logickými operacemi, aby byly takové operace možné, nebo efektivnější, pokud ALU může pracovat s více než jedním typem. C a C ++ provádějí takovou propagaci u objektů typu boolean, character, wide character, enumeration a short integer types that are promoted to int, and for objects of type float, which are promoted to double. Na rozdíl od některých jiných typů převodu propagace nikdy neztratí přesnost ani nezmění hodnotu uloženou v objektu.
V Javě :
int x = 3;
double y = 3.5;
System.out.println(x + y); // The output will be 6.5
Explicitní převod typů
Konverze explicitního typu je převod typu, který je explicitně definován v rámci programu (místo aby jej prováděl kompilátor pro implicitní převod typů). Je definován uživatelem v programu.
double da = 3.3;
double db = 3.3;
double dc = 3.4;
int result = (int)da + (int)db + (int)dc; // result == 9
// if implicit conversion would be used (as with "result = da + db + dc"), result would be equal to 10
Existuje několik druhů explicitní konverze.
- kontrolovány
- Před provedením převodu se provede kontrola za běhu, aby se zjistilo, zda typ cíle může obsahovat zdrojovou hodnotu. Pokud ne, vyvolá se chybový stav.
- nezaškrtnuto
- Žádná kontrola se neprovádí. Pokud typ cíle nemůže obsahovat zdrojovou hodnotu, výsledek není definován.
- bitový vzor
- Hrubá bitová reprezentace zdroje je zkopírována doslovně a je znovu interpretována podle typu cíle. Toho lze také dosáhnout pomocí aliasingu .
V objektově orientovaných programovacích jazycích mohou být objekty také downcastovány : odkaz na základní třídu je přetypován na některou z jejích odvozených tříd.
C# a C ++
V jazyce C# lze převod typů provádět bezpečným nebo nebezpečným (tj. Podobným C) způsobem, kterému se dříve říkalo kontrolované přetypování .
Animal animal = new Cat();
Bulldog b = (Bulldog) animal; // if (animal is Bulldog), stat.type(animal) is Bulldog, else an exception
b = animal as Bulldog; // if (animal is Bulldog), b = (Bulldog) animal, else b = null
animal = null;
b = animal as Bulldog; // b == null
V C ++ lze dosáhnout podobného efektu pomocí syntaxe přetypování ve stylu C ++ .
Animal* animal = new Cat;
Bulldog* b = static_cast<Bulldog*>(animal); // compiles only if either Animal or Bulldog is derived from the other (or same)
b = dynamic_cast<Bulldog*>(animal); // if (animal is Bulldog), b = (Bulldog*) animal, else b = nullptr
Bulldog& br = static_cast<Bulldog&>(*animal); // same as above, but an exception will be thrown if a nullptr was to be returned
// this is not seen in code where exception handling is avoided
animal = nullptr;
b = dynamic_cast<Bulldog*>(animal); // b == nullptr
delete animal; // always free resources
Eiffelova
V Eiffelově je pojem převodu typu integrován do pravidel typového systému. Pravidlo přiřazení říká, že úkol, jako například:
x := y
je platný tehdy a jen tehdy, pokud je typ jeho zdrojového výrazu y
v tomto případě kompatibilní s typem jeho cílové entity, x
v tomto případě. V tomto pravidle, kompatibilní s znamená, že typ zdrojového výrazu buď odpovídá cíli, nebo se na něj převádí . Shoda typů je definována známými pravidly pro polymorfismus v objektově orientovaném programování . Například ve výše uvedeném úkolu typ y
odpovídá typu, x
pokud je třída, na které y
je založen, potomkem toho, na kterém x
je založena.
Definice převodu typů v Eiffelu
Akce převodu typů v Eiffelu, konkrétně převody na a z nichž se převádí, jsou definovány jako:
Typ založený na CU třídy se převede na typ T na základě třídy CT (a T převede z U), pokud buď
- CT má postup převodu pomocí U jako typu převodu, popř
- CU má konverzní dotaz se seznamem T jako typem převodu
Příklad
Eiffel je plně kompatibilní jazyk pro Microsoft .NET Framework . Před vývojem .NET už měl Eiffel rozsáhlé knihovny tříd. Použití knihoven typů .NET, zejména u běžně používaných typů, jako jsou řetězce, představuje problém s převodem. Stávající software Eiffel používá třídy řetězců (například STRING_8
) z knihoven Eiffel, ale software Eiffel napsaný pro .NET musí System.String
v mnoha případech používat třídu řetězců .NET ( ), například při volání metod .NET, které očekávají položky .NET zadejte jako argumenty. Konverze těchto typů tam a zpět musí být co nejplynulejší.
my_string: STRING_8 -- Native Eiffel string
my_system_string: SYSTEM_STRING -- Native .NET string
...
my_string := my_system_string
Ve výše uvedeném kódu jsou deklarovány dva řetězce, jeden z každého jiného typu ( SYSTEM_STRING
je alias kompatibilní s Eiffelem pro System.String). Protože System.String
neodpovídá STRING_8
, pak výše uvedené přiřazení platí pouze v případě, že System.String
převede na STRING_8
.
Třída Eiffel STRING_8
má postup převodu make_from_cil
pro objekty typu System.String
. Postupy převodu jsou také vždy označeny jako postupy vytváření (podobné konstruktorům). Následuje výňatek ze STRING_8
třídy:
class STRING_8
...
create
make_from_cil
...
convert
make_from_cil ({SYSTEM_STRING})
...
Přítomnost postupu převodu dělá úkol:
my_string := my_system_string
sémanticky ekvivalentní:
create my_string.make_from_cil (my_system_string)
ve kterém my_string
je konstruován jako nový objekt typu STRING_8
s obsahem ekvivalentním obsahu my_system_string
.
Zpracování přiřazení s původním obráceným zdrojem a cílem:
my_system_string := my_string
třída STRING_8
také obsahuje dotaz na převod, to_cil
který vytvoří a System.String
z instance STRING_8
.
class STRING_8
...
create
make_from_cil
...
convert
make_from_cil ({SYSTEM_STRING})
to_cil: {SYSTEM_STRING}
...
Zadání:
my_system_string := my_string
pak se stává ekvivalentem:
my_system_string := my_string.to_cil
V Eiffelu je nastavení pro převod typů zahrnuto v kódu třídy, ale pak se zdá, že k tomu dochází automaticky jako konverze explicitního typu v klientském kódu. Zahrnuje nejen přiřazení, ale také další typy příloh, například substituci argumentů (parametrů).
Rez
Rust neposkytuje implicitní převod typů (nátlak) mezi primitivními typy. Konverzi explicitního typu (přetypování) lze však provést pomocí as
klíčového slova.
println!("1000 as a u16 is: {}", 1000 as u16);
Bezpečnostní problémy
Při hackování je typcasting zneužíváním převodu typů k dočasné změně datového typu proměnné z toho, jak byla původně definována. To poskytuje hackerům příležitosti, protože při převodu typu poté, co je proměnná „typecast“, aby se stala jiným datovým typem, bude kompilátor považovat tuto hacknutou proměnnou za nový datový typ pro tuto konkrétní operaci.
Viz také
Reference
externí odkazy
- Casting v Ada
- Casting v C ++
- Referenční příručka C ++ Proč nesnáším C ++ Cast Operators, Danny Kalev
- Casting v Javě
- Implicitní převody v C#
- Implicitní odesílání typu na Cppreference.com
- Statické a přeinterpretační odlitky v C ++
- Upcasting a downcasting ve F#