Conversie de tip ( typecasting , constrângere ) - în informatică , conversia unei valori de un tip într-o valoare de alt tip .
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).
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: 1Pentru 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 intPentru a evalua ultima expresie , compilatorul face ceva de genul acesta:
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
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 -2Cuvintele cheie greoaie sunt un memento pentru programator că tipul de turnare este plin de probleme.
Operațiunea static_castScop: 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:
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_castScop: 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_castScop: 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_castAtribuire: 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:
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ță