Típusöntés

Az oldal jelenlegi verzióját még nem ellenőrizték tapasztalt közreműködők, és jelentősen eltérhet a 2021. augusztus 21-én felülvizsgált verziótól ; az ellenőrzések 2 szerkesztést igényelnek .

Típuskonverzió ( typecasting , kényszer ) – az informatikában egy típusú érték átalakítása egy másik típusú értékre . 

Leírás

Léteznek típusfeliratok:

Az explicit szereposztást a programozó határozza meg a program szövegében a következőképpen:

Az implicit szereposztást fordító ( fordító vagy tolmács ) hajtja végre a nyelvi szabványban leírt szabályok szerint. A legtöbb nyelvi szabvány tiltja az implicit konverziót.

A gyengén tipizált objektumorientált nyelvekben, mint például a C++ , az öröklési mechanizmus úgy valósul meg, hogy az aktuális objektumra mutató mutató típusát az alaposztályba öntik (a típusbiztos nyelvekben , mint például az OCaml , a típusöntés fogalma alapvetően hiányzik, és az altípus-komponensre való hivatkozás megengedhetőségét a konzisztencia-ellenőrző mechanizmus típusai ellenőrzik fordításkor, és a közvetlen hozzáférés a gépi kódban marad).

Implicit típusú öntés

Implicit típusöntés C/C++-ban

Az implicit típusú öntés a következő esetekben fordul elő [1] :

Például egy bináris aritmetikai művelet végrehajtásakor az operandusok értékei ugyanabba a típusba kerülnek. Az öröklődés során a származtatott osztálymutatók az alaposztálymutatókba kerülnek.

Vegyünk egy példát C nyelven .

dupla d ; // valós típus long l ; // egész szám típusa int i ; // egész típus ha ( d > i ) d = i ; ha ( i > l ) l = i ; ha ( d == l ) d *= 2 ;

Összehasonlítási műveletek végrehajtásakor és hozzárendeléskor a különböző típusú változók implicit módon ugyanahhoz a típushoz kerülnek.

Az implicit konverzióknak mellékhatásai lehetnek. Például, ha egy szám valós típusát egész típusba öntjük, a tört részt levágjuk (a kerekítés nem történik meg) [2] . A fordított konverzió csökkentheti a pontosságot a valós és egész számok megjelenítési különbségei miatt. Például egy típusváltozóban ( IEEE 754 egyszeres pontosságú lebegőpontos szám ) a 16 777 217 szám nem tárolható a pontosság elvesztése nélkül, de  egy 32 bites egész típusú változóban igen. A pontosság elvesztése miatt az egész és valós típusokkal (például és ) reprezentált azonos számú összehasonlítási műveletek hamis eredményt adhatnak (a számok nem egyenlőek). float intintfloat

#include <stdio.h> int main ( érvénytelen ) { int i_value = 16777217 ; float f_value = 16777216.0 ; printf ( "Az egész szám:%d \n " , i_érték ); printf ( "A lebegés: %f \n " , f_érték ); printf ( "Egyenlőségük:%d \n " , i_érték == f_érték ); }

A fenti kód a következőt adja ki, ha a mérete  32 bites, és a fordító támogatja az IEEE 754 szabványt : int

Az egész szám: 16777217 Az úszószám: 16777216.000000 Egyenlõségük: 1

Explicit szereplők

Típus casting C-ben

Explicit típus-öntés esetén a típusnév zárójelben van megadva a változó vagy kifejezés előtt. Vegyünk egy példát.

int X ; int Y = 200 ; szén C = 30 ; X = ( int ) C * 10 + Y ; // A C változó az int típusba kerül

Az utolsó kifejezés kiértékeléséhez a fordító valami ilyesmit tesz:

  • először, egy karakter típusú változót bitkiterjesztéssel explicit módon egész típusúra öntünk ;Ccharint
  • a szorzási művelet operandusai kiértékelésre kerülnek. A bal oldali operandus típusa . A megfelelő operandus egy konstans , és az ilyen konstansok alapértelmezés szerint típusúak . Mivel a " * " operátor mindkét operandusa típusú , nem történik implicit öntés. A szorzás eredményének is van típusa ;int10intintint
  • az összeadási művelet operandusait kiértékelik. Bal oldali operandus – a szorzás eredményének típusa . A jobb oldali operandus egy típusú változó . Mivel a " + " operátor mindkét operandusa típusú , nincs implicit cast a közös típusra. Az összeadás eredménye is típusú ;intYintintint
  • megbízás végrehajtása. A bal oldali operandus egy típusú változó . A jobb oldali operandusnak, amely a " = " jeltől jobbra írt kifejezés kiértékelésének eredménye, szintén a típusa van . Mivel az " = " operátor mindkét operandusa azonos típusú, nincs implicit öntés.Xintint

Még így is előfordulhatnak hibák. A típus lehet aláírt ( ) vagy előjel nélküli ( ); az eredmény a fordító megvalósításától függ, és ezt a viselkedést a szabvány megengedi. Az előjel nélküli típus értéke az előjeles típusra konvertálva negatívnak bizonyulhat egyes processzorokon a gépi utasítások megvalósítása miatt . A félreértések elkerülése érdekében ajánlatos kifejezetten megadni az előjelességet a típushoz . charsigned charunsigned charcharintchar

Type casting C++ nyelven

Öt explicit típusú konverziós operátor van a C++- ban. Az első művelet, a zárójelek ( ) támogatottak a C -vel való kompatibilitás fenntartása érdekében . A maradék négy műveletet a következőképpen írjuk le (type_to)expression_from

xxx_cast < type_to >( kifejezés_ból )

Vegyünk egy példát.

y = static_cast < signed short > ( 65534 ); // az y változó -2-re lesz állítva

A nehézkes kulcsszavak emlékeztetik a programozót, hogy a típusöntés tele van problémákkal.

Művelet static_cast

Cél: Érvényes dobások.

A művelet egy kivétellel hasonló a zárójeles művelethez: nem ad mutatót nem kapcsolódó típusokra (a műveletet erre használják ). static_castreinterpret_cast

Alkalmazás:

  • konverzió numerikus és enum között, ideértve azt is, ha az implicit konverzió nem lehetséges ( ), vagy „A pontosság lehetséges elvesztése” figyelmeztetést eredményez ( );int enum classdouble float
  • mutatók öntése a típusra és fordítva;void*
  • mutatók átadása származtatott típusokra mutatók alaptípusokra és fordítva;
  • több túlterhelt funkció egyikének kiválasztása ;
bool myLess ( const wchar_t * , const wchar_t * ); bool myLess ( const std :: wstring & , const std :: wstring & ); std :: vektor < std :: wstring > lista ; std :: sort ( lista . kezdete (), lista . vége (), static_cast < bool ( * )( const std :: wstring & , const std :: wstring & ) > ( myLess ));
  • explicit hívás egyargumentumú konstruktorhoz vagy túlterhelt öntési művelet;
struct type { // konstruktor egy argumentummal az int típusba öntéséhez ( int ) ; // túlterhelt művelet öntési típushoz Type to type double operator double () const ; }; int main () { Típus x , y ; int i ; dupla d ; // konstruktor hívása egy argumentummal x = y + static_cast < Type > ( i ); // túlterhelt cast művelet meghívása d = static_cast < double > ( x ); return 0 ; } a konstruktornak több argumentuma is lehet, de ezeknek alapértelmezett értékeket kell adni; struct type { // konstruktor több argumentummal a Type-be önthető; // A 2. és az azt követő argumentumok alapértelmezett értékekre állítva Type ( int , int = 10 , float = 0.0 ); };
  • típusöntés a sablonokban (a fordító már eldönti, hogy milyen műveleteket használjon egy sablon specializálásakor);
  • a " " háromtagú feltételes művelet operandusainak öntése ?:ugyanabba a típusba (a 2. és 3. operandus értékének azonos típusúnak kell lennie);

Korlátozások expression_from: nem.

Korlátozások a type_tokövetkezőre: Biztosítani kell egy módot a kifejezés értékének expression_fromtípusra type_to, használóra operator type_tovagy konstruktorra való konvertálására.

A művelet előállít -e kódot: Általában igen (például túlterhelt cast vagy konstruktor művelet meghívása). static_cast

Logikai hibák forrásai: attól függ, hogy mit fog kezdeni a művelettel. Túlcsordulás, hatótávolságon kívüli, sőt (mutatókonverziók esetén) memóriakárosodás is lehetséges.

Példák.

// Találatszázalék lekérése. dupla billenő ( const int aHitCount , // találatok száma const int aShotCount // lövések száma ) { if ( aShotCount == 0 ) return 0.0 ; // A duplájára történő átküldés a valós (nem egész) osztás végrehajtásához történik static_cast < double > ( aHitCount * 100 ) / static_cast < double > ( aShotCount ); } // a következő sorok egyenértékűek // a static_cast művelet használata string s = static_cast < string > ( "Helló!" ); // konstruktor meghívása egy argumentummal string s = string ( "Hello!" ); // a zárójelek használatával műveleti string s = ( string ) "Hello!" ; string s = static_cast < string > ( 5 ); // nem fordít, a fordító nem talál megfelelő konstruktort Művelet dynamic_cast

Cél: az öröklődési hierarchia lebontása, speciális viselkedéssel, ha az objektum nem a kívánt típusú.

A művelet az RTTIexpression_from segítségével szerez információkat az objektum típusáról . Ha a típus vagy annak altípusa, akkor az öntést végrehajtják. Másképp: type_to

Korlátozások expression_from: A kifejezésnek hivatkozásnak vagy mutatónak kell lennie egy olyan objektumra, amely legalább egy virtuális funkcióval rendelkezik .

Megszorítások type_to: hivatkozás vagy mutató egy expression_fromtípus gyermekére.

A művelet generál-e kódot: igen. dynamic_cast

Logikai hibák lehetségesek, ha a művelet olyan argumentumot ad át, amelynek nincs típusa type_to, és nem ellenőrzi a mutató egyenlőségét (illetve ne kezelje a kivételt ). NULLstd::bad_cast

Művelet const_cast

Cél: módosító(k) eltávolítása/beszerelése , és/vagy . Ezt gyakran arra használják, hogy megkerüljék egy program vagy könyvtár rossz architektúráját, a C-t dokkolja a C++-szal, információt adjon át általános mutatókon , hogy egyidejűleg írjon egy függvény const és nem const változatát [3] ( van egy bypass C++14 [3] -on keresztül ). constvolatilemutablevoid*decltype(auto)

Korlátozások expression_from: A kifejezésnek hivatkozást vagy mutatót kell visszaadnia.

Korlátozások type_to: a típusnak type_tomeg kell egyeznie a kifejezés típusával expression_fromegészen módosító(k) ig , és . constvolatilemutable

A művelet generál-e kódot: nem. const_cast

Logikai hibák forrásai: A program módosíthat egy megváltoztathatatlan objektumot. Néha ez szegmentációs hibához vezethet , néha pedig egy szubrutin nem számíthat arra , [3] hogy az olvasásra elérhető memória hirtelen megváltozott.

Vegyük például a dinamikus könyvtár kódját .

#include <karakterlánc> // karakterlánc névtér használata std ; névtér { string s = "Wikipédia" ; // Globális változó // Metódus string::c_str() const char * } típusú mutatót ad vissza typedef char * PChar ; void __declspec ( dllexport ) WINAPI SomeDllFunction ( PChar & rMessage ) { // char const * konvertálása char * -ra rMessage = const_cast < char * > ( s . c_str () ); }

Amikor egy könyvtár betöltődik a folyamatmemóriába , új adatszegmenst hoz létre, amely globális változókat tartalmaz. A függvénykód a könyvtárban található, és meghívásakor egy mutatót ad vissza a globális osztályobjektum rejtett tagjára . A művelet a módosító eltávolítására szolgál . SomeDllFunction()stringconst_castconst

Művelet reinterpret_cast

Hozzárendelés: Gépelési szójáték  - Más (nem feltétlenül az adott típussal kompatibilis) típus hozzárendelése egy memóriahelyhez, a bitreprezentáció megőrzése mellett.

A kifejezés által visszaadott objektumot a expression_fromrendszer egy típusú objektumként kezeli type_to.

Korlátozások expression_from: A kifejezésnek sorszámú értéket kell visszaadnia (bármilyen egész, logikai érték vagy enum ), mutatót vagy hivatkozást. boolenum

Korlátozások type_to:

  • Ha expression_fromsorszámú típusú értéket vagy mutatót ad vissza, a típus type_tolehet sorszámú típus vagy mutató.
  • Ha expression_fromhivatkozást ad vissza, akkor a típusnak type_tohivatkozásnak kell lennie.

A művelet generál-e kódot: nem. reinterpret_cast

A logikai hibák forrásai. Előfordulhat , hogy a kifejezés által visszaadott objektum expression_fromnem típusú type_to. Ennek ellenőrzésére nincs mód, a programozó teljes felelősséget vállal az átalakítás helyességéért.

Vegye figyelembe a példákat.

// Igazat ad vissza, ha x véges. // Hamis értéket ad vissza, ha x szám ∞ vagy NaN. bool isfinite ( double const x ) { // konverzió double const -> uint64_t const & uint64_t const & y = reinterpret_cast < uint64_t const & > ( x ); return ( ( y & UINT64_C ( 0x7FF0000000000000 ) ) != UINT64_C ( 0x7FF0000000000000 ) ); } // egy ideiglenes érték címének megkísérlése long const & y = reinterpret_cast < long const & > ( x + 5.0 ); // hiba: az x + 5.0 kifejezés nem hivatkozás

Lásd még

Jegyzetek

  1. cppreference.com. Implicit konverziók Archiválva : 2014. december 18. a Wayback Machine -nél .
  2. open-std.org ISO/IEC 9899:2018 C programozási nyelvi szabvány (C18) Archiválva : 2020. július 22., a Wayback Machine 6.3.1.4 Valós lebegő és egész szám.
  3. 1 2 3 C++ Weekly - Ep 283 - Hagyd abba a const_cast használatát! - Youtube . Letöltve: 2021. augusztus 20. Az eredetiből archiválva : 2021. augusztus 20.

Linkek