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 floatto 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_valuena 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:

  1. floatna intpříčinách zkrácení , tj odstranění nepatrné části.
  2. doublek floatpříčinám zaokrouhlování číslice.
  3. longna intpříč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 yv tomto případě kompatibilní s typem jeho cílové entity, xv 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 yodpovídá typu, xpokud je třída, na které yje založen, potomkem toho, na kterém xje 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.Stringv 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_STRINGje alias kompatibilní s Eiffelem pro System.String). Protože System.Stringneodpovídá STRING_8, pak výše uvedené přiřazení platí pouze v případě, že System.Stringpřevede na STRING_8.

Třída Eiffel STRING_8má postup převodu make_from_cilpro 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_8tří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_stringje konstruován jako nový objekt typu STRING_8s 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_8také obsahuje dotaz na převod, to_cilkterý vytvoří a System.Stringz 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í asklíč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