Převody typu a typ bezpečnosti (C++)
Tento dokument identifikuje typ převodu potíží a popisuje, jak jim zabránit v kódu jazyka C++.
Při psaní programu C++ je důležité zajistit, že je bezpečný.To znamená, že každé proměnné argument funkce a funkce vrátí hodnotu je ukládání přijatelný druh dat a že operace, které se týkají hodnot různých datových typů "smysl" a nezpůsobí ztrátu dat, nesprávného výkladu bit vzorky nebo poškození paměti.Program, který nikdy explicitně nebo implicitně převede hodnoty z jednoho typu na jiný je typově bezpečný podle definice.Však zadat převody, i nebezpečné převody, je někdy třeba.Máte-li například k ukládání výsledků okna plovoucí bod operace v proměnné typu int, nebo bude pravděpodobně nutné předat hodnotu nepodepsaný int na funkci, která přebírá podepsané int.Oba příklady ilustrují bezpečné převody, protože může způsobit ztrátu dat nebo re-interpretation hodnotu.
Kompilátor zjistí nebezpečný převodu, vydává chybu nebo upozornění.Přestane k chybě kompilace; upozornění umožňuje kompilaci, chcete-li pokračovat, ale označuje možnou chybu v kódu.Avšak i v případě, že váš program zkompiluje bez upozornění, stále může obsahovat kód, který vede k implicitních převodech typů, které poskytují nesprávné výsledky.Typ chyby lze rovněž zaveden explicitní převody nebo nádech v kódu.
Implicitní typový převod
Pokud výraz obsahuje operandy různých předdefinovaných typů a jsou k dispozici žádné explicitní přetypování, kompilátor používá integrované standardních převodech Chcete-li převést jeden z operandů tak, aby odpovídaly typy.Kompilátor pokusí převody v přesně vymezené sekvenci až do úspěšného vytvoření připojení.Je-li vybraný přepočet povýšení, nevydává kompilátoru upozornění.Je-li převod zužující, vydá upozornění na možnou ztrátu dat.Zda dojde ke ztrátě skutečných dat závisí na skutečné hodnoty, které jsou zapojené, ale doporučujeme považovat upozornění jako chyby.Pokud se jedná o uživatelem definovaný typ, kompilátor pokusí použít převody, které jste zadali v definici třídy.Pokud jej nemůžete najít přijatelné převodu, kompilátor vydává chybu a program zkompilován.Další informace o pravidla, která řídí standardních převodech naleznete v tématu Standardní.Další informace o uživatelem definovaný převod, viz Uživatelem definované převody (C++/CLI).
Rozšiřující převody (podpora)
V rozšiřující převod přiřazena hodnota proměnné menší větší proměnné bez ztráty dat..Protože rozšiřující převody jsou vždy bezpečné, kompilátor je provede bez zásahu uživatele a nevydává upozornění.Tyto převody jsou rozšiřující převody.
Od |
Akce |
---|---|
Všechny podepsané nebo nepodepsané integrálního typu s výjimkou long long nebo__int64 |
double |
bool nebo char |
Ostatní předdefinovaný typ |
short nebo wchar_t |
int, long, long long |
int, long |
long long |
float |
double |
Zužující převody (vynucení)
Kompilátor implicitně provede zužující převody, ale upozorňuje potenciální ztrátě dat.Přijmout tato upozornění velmi vážně.Pokud jste si jisti, že bez ztráty dat. vzhledem k tomu hodnoty do většího proměnné vždy vejde do menší proměnnou, pak přidáte explicitní přetypování tak, aby kompilátor bude nadále vydávat varování.Pokud si nejste jisti, že převod je bezpečný, do kódu přidáte nějaký druh zaškrtnutí runtime zpracování možnou ztrátu dat tak, že nezpůsobí sady poskytují nesprávné výsledky.Návrhy o způsobu zpracování tohoto scénáře, viz Jak: zpracování zužující převody (C++).
Jakýkoli převod z plovoucí bod typu na integrální typ. totiž zužujícího převodu desetinnou část plovoucí přejděte hodnotu je zahozen a ztracené.
Následující příklad kódu ukazuje některé implicitní zužující převody a varování, které vydá pro ně.
int i = INT_MAX + 1; //warning C4307:'+':integral constant overflow
wchar_t wch = 'A'; //OK
char c = wch; // warning C4244:'initializing':conversion from 'wchar_t'
// to 'char', possible loss of data
unsigned char c2 = 0xfffe; //warning C4305:'initializing':truncation from
// 'int' to 'unsigned char'
int j = 1.9f; // warning C4244:'initializing':conversion from 'float' to
// 'int', possible loss of data
int k = 7.7; // warning C4244:'initializing':conversion from 'double' to
// 'int', possible loss of data
Podepsáno - nepodepsané převody
Podepsané integrálního typu a jeho protějšek nepodepsané mají vždy stejnou velikost, ale liší se jak bitový vzorec interpretována pro hodnotu transformace.Následující příklad kódu ukazuje, co se stane, když stejný vzor bit interpretován jako hodnotu podepsané i nepodepsané hodnoty.Bitový vzor, který je uložen v obou num a num2 nikdy změní z hodnoty zobrazené v předchozí ilustraci.
using namespace std;
unsigned short num = numeric_limits<unsigned short>::max(); // #include <limits>
short num2 = num;
cout << "unsigned val = " << num << " signed val = " << num2 << endl;
// Prints: unsigned val = 65535 signed val = -1
// Go the other way.
num2 = -1;
num = num2;
cout << "unsigned val = " << num << " signed val = " << num2 << endl;
// Prints: unsigned val = 65535 signed val = -1
Všimněte si, že hodnoty jsou reinterpreted v obou směrech.Pokud váš program vytváří odlišné výsledky ve kterých se zdá být znaménko hodnoty obrácený očekávání, vyhledejte implicitní převody mezi podepsaných i nepodepsaných integrální typy.V následujícím příkladu výsledkem výrazu (0 – 1) je implicitně převeden z int na unsigned int při uložení v num.To způsobí, že bitový vzor, chcete-li být reinterpreted.
unsigned int u3 = 0 - 1;
cout << u3 << endl; // prints 4294967295
O implicitních převodech mezi podepsaných i nepodepsaných integrální typy upozornění kompilátoru.Proto doporučujeme, abyste zcela zabránit podepsané na nepodepsané převody.Pokud nelze vyhnout se jim, pak přidejte do kódu modulu runtime kontroly ke zjištění, zda hodnota převáděného je větší než nebo rovno nule a menší nebo rovna maximální hodnotu podepsané typu.Hodnoty v této oblasti bude přenos z podepsané nepodepsaný nebo bez znaménka na podepsané bez právě reinterpreted.
Ukazatel převody
V mnoha výrazy pole ve stylu jazyka je implicitně převeden na ukazatel na první prvek pole a konstantní převodu může dojít bez zásahu uživatele.I když je to vhodné, je také potenciálně náchylné k chybě.Například následující příklad špatně navržený kód, se jeví jako nesmyslný a ještě bude zkompilovat v aplikaci Visual C++ a vytváří výsledek, "p".Nejprve je konstantní literál řetězce "Help" převedeny na char* který odkazuje na první prvek pole; Tento ukazatel je zvýšen tři prvky, takže nyní odkazuje na poslední prvek "p".
char* s = "Help" + 3;
Explicitní převody (nádech)
Pomocí operace přetypování dáte pokyn kompilátoru k převodu hodnoty jednoho typu na jiný typ.Kompilátor vyvolá chybu v některých případech, pokud jsou dva typy naprosto nesouvisející, ale v ostatních případech ji nevyvolá chybu i v případě, že operace není typově bezpečný.Nádech používejte opatrně, protože jakýkoli převod z jednoho typu je možný zdroj chyby programu.Však nádech je někdy třeba a ne všechny nádechy jsou stejně nebezpečné.Efektivní využívání přetypování je v případě, že váš kód provádí zužujícího převodu a víte, že převod není příčinou program nesprávné výsledky.Ve skutečnosti to říká kompilátoru, že víte, co byste a ukončení, je bothering s varováním o něm.Dalším použitím je přetypovat z ukazatel odvozených tříd ukazatele základní třídy.Dalším použitím je okamžitě převést const- strukturou proměnné předat funkci, která vyžaduje než -const argument.Většina z těchto operací přetypování zahrnovat určité riziko.
V programování C styl se používá stejné operátor přetypování ve stylu C pro všechny druhy nádech.
(int) x; // old-style cast, old-style syntax
int(x); // old-style cast, functional syntax
Operátor přetypování ve stylu C je totožný s (volání operátor) a proto je nevýrazné v kódu a snadno přehlédnout.Obě jsou chybné, protože se nacházejí obtížně rozpoznat na první pohled nebo vyhledat a ty jsou natolik různorodé, vyvolat libovolnou kombinaci static, const, a reinterpret_cast.Přemýšlet nad tím, co přetypování starým stylem ve skutečnosti nemá, může být složité a náchylné k chybě.Ze všech těchto důvodů při přetypování je vyžadováno, doporučujeme použít jednu z následujících operátorů C++ nádech, což v některých případech jsou podstatně více bezpečný a který express mnohem více explicitně programovací záměr:
static_cast, pouze pro nádech, která jsou kontrolována při kompilaci čas.static_castVrátí chybu, pokud kompilátor zjistí, že se pokoušíte přetypovávat mezi typy, které nejsou zcela kompatibilní.Můžete také ji přetypovávat mezi ukazatel na základní a ukazatel odvozený, ale kompilátor nemůže vždy určit, zda takové převody budou zabezpečeny za běhu.
double d = 1.58947; int i = d; // warning C4244 possible loss of data int j = static_cast<int>(d); // No warning. string s = static_cast<string>(d); // Error C2440:cannot convert from // double to std:string // No error but not necessarily safe. Base* b = new Base(); Derived* d2 = static_cast<Derived*>(b);
Další informace naleznete v tématu static_cast.
dynamic_cast, pro bezpečné, kontrolovány runtime nádech ukazatel základní ukazatel odvozené.A dynamic_cast je bezpečnější než static_cast downcasts, ale modul runtime zahrnuje kontrolu některých režii.
Base* b = new Base(); // Run-time check to determine whether b is actually a Derived* Derived* d3 = dynamic_cast<Derived*>(b); // If b was originally a Derived*, then d3 is a valid pointer. if(d3) { // Safe to call Derived method. cout << d3->DoSomethingMore() << endl; } else { // Run-time check failed. cout << "d3 is null" << endl; } //Output: d3 is null;
Další informace naleznete v tématu dynamic_cast.
const_cast, pro obsazení pryč const- strukturou proměnné nebo převod non -const proměnnou, která má být const.Obsazení pryč const-strukturou pomocí tohoto operátoru je stejně jako náchylný tak, jak se používá přetypování ve stylu C, ovšem s const-cast méně pravděpodobný omylem provést přetypování.Někdy musíte přetypovat pryč const-strukturou proměnné, například k předání const proměnnou pro funkci, která přebírá než-const parametr.Následující příklad ukazuje, jak to provést.
void Func(double& d) { ... } void ConstCast() { const double pi = 3.14; Func(const_cast<double&>(pi)); //No error. }
Další informace naleznete v tématu const_cast.
reinterpret_cast, pro přetypování mezi nezávislým typy, jako je například pointer na int.
[!POZNÁMKA]
Tento operátor přetypování se nepoužívá tak často, jako ostatní a má není zaručena přenosný jinými kompilátory.
Následující příklad ukazuje, jak reinterpret_cast se liší od static_cast.
const char* str = "hello"; int i = static_cast<int>(str);//error C2440: 'static_cast' : cannot // convert from 'const char *' to 'int' int j = (int)str; // C-style cast. Did the programmer really intend // to do this? int k = reinterpret_cast<int>(str);// Programming intent is clear. // However, it is not 64-bit safe.
Další informace naleznete v tématu reinterpret_cast operátora.
Viz také
Koncepty
Systém typů C++ (Příručka programování moderních C++)