Tip turnare

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 21 august 2021; verificările necesită 2 modificări .

Conversie de tip ( typecasting , constrângere ) - în informatică , conversia unei valori de un tip într-o valoare de alt tip . 

Descriere

Există modele de tip:

Distribuția explicită este specificată de programator în textul programului folosind:

O distribuție implicită este efectuată de un traducător ( compilator sau interpret ) conform regulilor descrise în standardul lingvistic. Majoritatea standardelor lingvistice interzic conversiile implicite.

În limbajele orientate pe obiecte slab tipizate , cum ar fi C++ , mecanismul de moștenire este implementat prin turnarea tipului indicatorului către obiectul curent în clasa de bază (în limbaje sigure de tip, cum ar fi OCaml , conceptul de tip casting). este fundamental absentă, iar admisibilitatea referirii la componenta de subtip este controlată de tipurile de mecanism de verificare a coerenței la momentul compilării, iar accesul direct rămâne în codul mașinii).

Casting de tip implicit

Casting tip implicit în C/C++

Turnarea de tip implicit are loc în următoarele cazuri [1] :

De exemplu, atunci când se efectuează o operație aritmetică binară, valorile operanzilor sunt turnate la același tip. În moștenire, pointerii de clasă derivate sunt transformați în pointerii de clasă de bază.

Luați în considerare un exemplu în limbajul C.

dublu d ; // tip real long l ; // tip întreg int i ; // tip întreg dacă ( d > i ) d = i ; dacă ( i > l ) l = i ; dacă ( d == l ) d *= 2 ;

La efectuarea operațiunilor de comparare și la atribuire, variabilele de diferite tipuri sunt implicit turnate la același tip.

Conversiile implicite pot avea efecte secundare. De exemplu, atunci când turnați un număr de tip real într-un tip întreg, partea fracțională este tăiată ( rotunjirea nu este efectuată) [2] . Conversia inversă poate reduce acuratețea din cauza diferențelor de reprezentare a numerelor reale și întregi. De exemplu, într-o variabilă de tip ( număr cu virgulă mobilă cu precizie unică IEEE 754 ), nu puteți stoca numărul 16.777.217 fără pierderi de precizie, dar  puteți într-o variabilă de tip întreg de 32 de biți. Din cauza pierderii preciziei, operațiunile de comparare a aceluiași număr reprezentat prin tipuri întregi și reale (de exemplu, și ) pot da rezultate false (numerele pot să nu fie egale). float intintfloat

#include <stdio.h> int main ( void ) { int i_valoare = 16777217 ; float f_value = 16777216,0 ; printf ( "Numărul întreg este:%d \n " , i_valoare ); printf ( "Float este: %f \n " , f_value ); printf ( "Egalitatea lor:%d \n " , i_value == f_value ); }

Codul de mai sus va afișa următoarele dacă dimensiunea  este de 32 de biți și compilatorul acceptă standardul IEEE 754 : int

Numărul întreg este: 16777217 Plutitorul este: 16777216.000000 Egalitatea lor: 1

Distribuție explicită

Tip casting în C

Pentru turnarea explicită a tipului, numele tipului este specificat între paranteze înainte de variabilă sau expresie. Luați în considerare un exemplu.

int X ; int Y = 200 ; char C = 30 ; X = ( int ) C * 10 + Y ; // Variabila C este turnată pentru a tasta int

Pentru a evalua ultima expresie , compilatorul face ceva de genul acesta:

  • mai întâi, o variabilă de tip caracter este turnată în mod explicit la un tip întreg prin extensia de biți ;Ccharint
  • se evaluează operanzii pentru operaţia de înmulţire. Operandul din stânga este de tip . Operandul drept este o constantă , iar astfel de constante sunt de tip implicit . Deoarece ambii operanzi ai operatorului " * " sunt de tip , nu se efectuează nicio turnare implicită. Rezultatul înmulțirii are și tipul ;int10intintint
  • se evaluează operanzii operaţiei de adunare. Operand stânga — rezultatul înmulțirii are tipul . Operandul din dreapta este o variabilă de tip . Deoarece ambii operanzi ai operatorului " + " sunt de tip , nu există nicio interpretare implicită a tipului comun. Rezultatul adunării este, de asemenea, de tip ;intYintintint
  • executarea misiunii. Operandul din stânga este o variabilă de tip . Operandul drept, rezultat al evaluării expresiei scrise în dreapta semnului „ = ” are și tipul . Deoarece ambii operanzi ai operatorului " = " sunt de același tip, nu există nicio turnare implicită.Xintint

Chiar și așa, greșelile sunt posibile. Tipul poate fi fie semnat ( ) fie nesemnat ( ); rezultatul depinde de implementarea compilatorului și acest comportament este permis de standard. Valoarea unui tip nesemnat atunci când este convertit într-un tip semnat se poate dovedi a fi negativă din cauza implementării instrucțiunilor mașinii pe unele procesoare . Pentru a evita ambiguitățile, se recomandă să specificați în mod explicit semnătura pentru tipul . charsigned charunsigned charcharintchar

Tastați casting în C++

Există cinci operatori de conversie de tip explicit în C++ . Prima operație, parantezele ( ), este acceptată pentru a menține compatibilitatea cu C . Celelalte patru operațiuni sunt scrise ca (type_to)expression_from

xxx_cast < type_to >( expression_from )

Luați în considerare un exemplu.

y = static_cast < semnat scurt > ( 65534 ); // variabila y va fi setată la -2

Cuvintele cheie greoaie sunt un memento pentru programator că tipul de turnare este plin de probleme.

Operațiunea static_cast

Scop: distribuții valide.

Operația este similară cu operația de paranteză cu o excepție: nu aruncă pointeri către tipuri neînrudite (operația este folosită pentru aceasta ). static_castreinterpret_cast

Aplicație:

  • conversie între numere și enumerare, inclusiv atunci când conversia implicită nu este posibilă ( ) sau are ca rezultat un avertisment „Posibilă pierdere de precizie” ( );int enum classdouble float
  • aruncarea de indicatori la tip și invers;void*
  • turnarea de pointeri către tipuri derivate în pointeri către tipuri de bază și invers;
  • selectarea uneia dintre mai multe funcții supraîncărcate ;
bool myLess ( const wchar_t * , const wchar_t * ); bool myLess ( const std :: wstring & , const std :: wstring & ); std :: vector < std :: wstring > listă ; std :: sort ( list . begin (), list . end (), static_cast < bool ( * )( const std :: wstring & , const std :: wstring & ) > ( myLess ));
  • un apel explicit la un constructor cu un singur argument sau o operație de turnare supraîncărcată;
tip structura { // constructor cu un argument pentru a turna int la Type Type ( int ); // operație supraîncărcată pentru tipul de turnare Type to type double operator double () const ; }; int main () { Tip x , y ; int i ; dublu d ; // apelează constructorul cu un argument x = y + static_cast < Type > ( i ); // apelarea unei operații de turnare supraîncărcate d = static_cast < double > ( x ); returnează 0 ; } constructorul poate avea mai multe argumente, dar trebuie să li se dea valori implicite; tip structura { // constructor cu mai multe argumente pentru a turna int la Type; // Al doilea și următoarele argumente setate la valorile implicite Type ( int , int = 10 , float = 0.0 ); };
  • introducerea tipului în șabloane (compilatorul decide deja ce operații să folosească atunci când specializează un șablon);
  • turnarea operanzilor operației condiționale ternare „ ?:” la același tip (valorile operanzilor 2 și 3 trebuie să aibă același tip);

Restricții privind expression_from: nu.

Restricții privind type_to: Trebuie să existe o modalitate de a converti valoarea expresiei expression_fromîn tip type_to, folosind operator type_tosau constructor.

Operația produce cod: În general, da (de exemplu, apelarea unei operații de distribuție sau de constructor supraîncărcate). static_cast

Surse de erori logice: depind de ce vei face cu operația. Sunt posibile depășiri, în afara intervalului și chiar (pentru conversiile pointerului) coruperea memoriei.

Exemple.

// Obțineți procentajul de accesare. dublu -tippercent ( const int aHitCount , // numărul de accesări const int aShotCount // numărul de lovituri ) { if ( aShotCount == 0 ) returnează 0,0 ; // Castarea la dublu se face pentru a efectua returnarea diviziunii reale (non-intger) static_cast < double > ( aHitCount * 100 ) / static_cast < double > ( aShotCount ); } // următoarele linii sunt echivalente // utilizând operația static_cast șir s = static_cast < șir > ( "Bună!" ); // apelează constructorul cu un singur argument șir s = șir ( "Bună ziua!" ); // folosind operația cu paranteze șir s = ( șir ) "Bună ziua!" ; șir s = static_cast < șir > ( 5 ); // nu se compila, compilatorul nu poate găsi un constructor potrivit Operațiunea dynamic_cast

Scop: distrugerea ierarhiei de moștenire, cu comportament special dacă obiectul nu este de tipul dorit.

Operația obține informații despre tipul obiectului expression_fromfolosind RTTI . Dacă tipul este type_tosau un subtip al acestuia, distribuția este efectuată. In caz contrar:

Restricții privind expression_from: expresia trebuie să fie o referință sau un pointer către un obiect care are cel puțin o funcție virtuală .

Constrângeri privind type_to: o referință sau un indicator către un copil de un expression_fromtip.

Operația generează un cod: da. dynamic_cast

Erorile logice sunt posibile dacă operația trece un argument care nu are tip type_toși nu verifică indicatorul pentru egalitate (respectiv, nu gestionați excepția ). NULLstd::bad_cast

Operațiunea const_cast

Scop: eliminarea/instalarea modificatorilor și /sau . Adesea, aceasta este folosită pentru a ocoli arhitectura proastă a unui program sau a unei biblioteci, pentru a andoca C cu C++, pentru a trece informații prin pointeri generici , pentru a scrie simultan o versiune const și non-const a unei funcții [3] ( există o ocolire în C++14 [3] ). constvolatilemutablevoid*decltype(auto)

Restricții privind expression_from: Expresia trebuie să returneze o referință sau un pointer.

Restricții privind type_to: tipul type_totrebuie să se potrivească cu tipul expresiei expression_frompână la modificator(i ) și . constvolatilemutable

Operația generează un cod: nu. const_cast

Surse de erori logice: Un program poate modifica un obiect imuabil. Uneori, acest lucru poate duce la o eroare de segmentare , uneori o subrutină nu se poate aștepta [3] ca memoria pe care a pus-o la dispoziție pentru citire să se schimbe brusc.

De exemplu, luați în considerare codul bibliotecii dinamice .

#include <șir> // șir folosind namespace std ; spatiu de nume { șir s = „Wikipedia” ; // Variabila globala // metoda string::c_str() returneaza un pointer de tipul const char * } typedef char * PChar ; void __declspec ( dllexport ) WINAPI SomeDllFunction ( PChar & rMessage ) { // convertesc char const * în char * rMessage = const_cast < char * > ( s . c_str () ); }

Când o bibliotecă este încărcată în memoria de proces , aceasta creează un nou segment de date care deține variabile globale. Codul funcției se află în bibliotecă și, atunci când este apelat, returnează un pointer către un membru ascuns al obiectului clasei globale . Operația este folosită pentru a elimina modificatorul . SomeDllFunction()stringconst_castconst

Operațiunea reinterpret_cast

Atribuire: Tastare joc de cuvinte  - Atribuirea unui tip diferit (nu neapărat compatibil cu cel dat) unei locații de memorie, păstrând în același timp reprezentarea biților.

Obiectul returnat de expresie expression_fromeste tratat ca un obiect de tip type_to.

Restricții privind expression_from: Expresia trebuie să returneze o valoare de tip ordinal (orice număr întreg, boolean sau enumerare ), un pointer sau o referință. boolenum

Restricții privind type_to:

  • Dacă expression_fromreturnează o valoare de tip ordinal sau un pointer, tipul type_topoate fi un tip ordinal sau un pointer.
  • Dacă expression_fromreturnează o referință, tipul type_totrebuie să fie o referință.

Operația generează un cod: nu. reinterpret_cast

Surse de erori logice. Obiectul returnat de expresie expression_frompoate să nu fie de tipul type_to. Nu există nicio modalitate de a verifica acest lucru, programatorul își asumă întreaga responsabilitate pentru corectitudinea conversiei.

Luați în considerare exemple.

// Returnează adevărat dacă x este finit. // Returnează fals dacă numărul x este ∞ sau NaN. bool este finit ( const dublu x ) { // conversie double const -> uint64_t const & uint64_t const & y = reinterpret_cast < uint64_t const & > ( x ); return ( ( y & UINT64_C ( 0x7FF0000000000000 ) ) != UINT64_C ( 0x7FF0000000000000 ) ); } // încercarea de a obține adresa unei valori temporare long const & y = reinterpret_cast < long const & > ( x + 5.0 ); // eroare: expresia x + 5.0 nu este o referință

Vezi și

Note

  1. cppreference.com. Conversii implicite Arhivat 18 decembrie 2014 la Wayback Machine .
  2. open-std.org ISO/IEC 9899:2018 C Standardul limbajului de programare (C18) Arhivat la 22 iulie 2020 la Wayback Machine 6.3.1.4 Flotante reală și întreg.
  3. 1 2 3 C++ Weekly - Ep 283 - Nu mai folosiți const_cast! - Youtube . Preluat la 20 august 2021. Arhivat din original la 20 august 2021.

Link -uri