C ++

Standardní převody v C ++

Standardní převody v C ++
V C ++ existují dva typy entit, základní typy a složené typy. Základní typy jsou skalární typy. Složené typy jsou zbytek typů entit. Převod může probíhat z jednoho typu entity na jiný vhodný typ. Zvažte následující program:

#zahrnout
#zahrnout
pomocí jmenného prostoru std;
int main ()

int rt1 = sqrt (5);
int rt2 = sqrt (8);
cout<návrat 0;

Výstup je 2, 2, což znamená, že program vrátil druhou odmocninu z 5 jako 2 a druhou odmocninu z 8 také jako 2. Takže první dva výroky v hlavní() funkce umocnily odpovědi na druhou odmocninu z 5 a druhou odmocninu z 8. Tento článek se nezabývá podlahou nebo stropem v jazyce C++. Tento článek spíše pojednává o převodu jednoho typu C ++ na jiný vhodný typ C ++; označující jakoukoli aproximaci provedené hodnoty, ztrátu přesnosti nebo přidané či odebrané omezení. Základní znalost C ++ je předpokladem k pochopení tohoto článku.

Obsah článku

  • Integrální převody
  • Konverze s plovoucí desetinnou čárkou
  • Plovoucí integrální převody
  • Hodnocení celočíselných konverzí
  • Integrální propagace
  • Obvyklé aritmetické převody
  • Propagace s plovoucí desetinnou čárkou
  • Konverze ukazatele
  • Převod funkce na ukazatel
  • Booleovské převody
  • Lvalue, prvalue a xvalue
  • Xvalue
  • Převody hodnot na hodnotu r-rvalue
  • Konverze z pole na ukazatel
  • Konverze funkce na ukazatel
  • Dočasné převody materializace
  • Konverze kvalifikace
  • Závěr

Integrální převody

Integrální převody jsou celočíselné převody. Nepodepsaná celá čísla zahrnují „nepodepsaný znak“, „nepodepsaný krátký int“, „nepodepsaný int“, „nepodepsaný dlouhý int“ a „nepodepsaný dlouhý dlouhý int“.„Odpovídající celá čísla se znaménkem zahrnují„ podepsaný znak “,„ krátký int “,„ int “,„ dlouhý int “a„ dlouhý dlouhý int “.„Každý typ int by měl být uchováván v tolika bajtech jako jeho předchůdce. U většiny systémů lze jeden typ entity bez problémů převést na odpovídající typ. K problému dochází při převodu z většího typu rozsahu na menší typ rozsahu nebo při převodu podepsaného čísla na odpovídající nepodepsané číslo.

Každý kompilátor má maximální hodnotu, kterou může mít pro krátký int. Pokud je krátkému int přiděleno číslo vyšší než toto maximum, určené pro int, kompilátor bude postupovat podle nějakého algoritmu a vrátí číslo v rozsahu short int. Pokud má programátor štěstí, kompilátor upozorní na potíže s použitím nevhodného převodu. Stejné vysvětlení platí pro převody jiných typů int.

Uživatel by měl nahlédnout do dokumentace kompilátoru a určit mezní hodnoty pro každý typ entity.

Pokud se má záporné podepsané krátké int číslo převést na nepodepsané krátké int číslo, kompilátor bude postupovat podle nějakého algoritmu a vrátí kladné číslo v rozsahu nepodepsaného krátkého int. Tomuto druhu přeměny je třeba se vyhnout. Stejné vysvětlení platí pro převody jiných typů int.

Jakékoli celé číslo, kromě 0, lze převést na booleovskou hodnotu true. 0 se převede na Boolean false. Následující kód to ilustruje:

int a = -27647;
float b = 2.5;
int c = 0;
bool a1 = a;
bool b1 = b;
bool cl = c;
cout<cout<cout<Výstupem je:

1 za pravdu
1 za pravdu
0 pro false

Konverze s plovoucí desetinnou čárkou

Typy s plovoucí desetinnou čárkou zahrnují „float“, „double“ a „long double.„Typy s plovoucí desetinnou čárkou nejsou seskupeny do podepsaných a nepodepsaných, jako celá čísla. Každý typ může mít podepsané nebo nepodepsané číslo. Typ s plovoucí desetinnou čárkou by měl mít alespoň stejnou přesnost jako jeho předchůdce. To znamená, že „long double“ by měl mít stejnou nebo větší přesnost na „double“ a „double“ by měl mít stejnou nebo větší přesnost na „float“.“

Pamatujte, že rozsah typu s plovoucí desetinnou čárkou není spojitý; spíše je to po malých krocích. Čím větší je přesnost typu, tím menší jsou kroky a tím větší je počet bajtů pro uložení čísla. Když se tedy číslo s plovoucí desetinnou čárkou převede z typu s nižší přesností na typ s vyšší přesností, musí programátor přijmout falešné zvýšení přesnosti a možné zvýšení počtu bajtů pro ukládání čísel. Když je číslo s plovoucí desetinnou čárkou převedeno z typu s vyšší přesností na typ s nižší přesností, musí programátor přijmout ztrátu přesnosti. Pokud je třeba snížit počet bajtů pro ukládání čísel, kompilátor bude postupovat podle nějakého algoritmu a vrátí číslo jako náhradu (což pravděpodobně programátor nechce). Mějte také na paměti problémy mimo dosah.

Plovoucí integrální převody

Číslo s plovoucí desetinnou čárkou se převede na celé číslo zkrácením zlomkové části. Následující kód to ilustruje:

float f = 56.953;
int i = f;
cout<Výstup je 56. Rozsahy pro plovoucí a celé číslo musí být kompatibilní.

Když je celé číslo převedeno na plovák, hodnota zobrazená jako plovák je stejná, jako byla zadána jako celé číslo. Plovoucí ekvivalent však může být přesná hodnota nebo může mít nepatrný zlomkový rozdíl, který se nezobrazí. Důvod pro zlomkový rozdíl spočívá v tom, že čísla s plovoucí desetinnou čárkou jsou v počítači zastoupena v malých zlomkových krocích, a proto by přesné představování celého čísla byla náhoda. Přestože je celé číslo zobrazené jako plovák stejné, jako bylo zadáno, může být zobrazení přibližné k tomu, co je uloženo.

Hodnocení celočíselných konverzí

Jakýkoli celočíselný typ má hodnost, která mu byla přidělena. Toto hodnocení pomáhá při konverzi. Hodnocení je relativní; pozice nejsou na pevných úrovních. Kromě char a podepsaného char, žádná dvě podepsaná celá čísla nemají stejnou hodnost (za předpokladu, že char je podepsán). Celé typy bez znaménka mají stejné hodnocení jako jejich odpovídající celočíselné typy se znaménkem. Pořadí je následující:

  • Za předpokladu, že znak je podepsán, pak char a podepsaný znak mají stejnou hodnost.
  • Pořadí celočíselného typu se znaménkem je větší než pořadí celočíselného typu se znaménkem u menšího počtu bajtů úložiště. Takže hodnost podepsaného dlouhého dlouhého int je větší než hodnost podepsaného dlouhého int, což je větší než hodnost podepsaného dlouhého int, což je větší než hodnost podepsaného dlouhého int, což je větší než hodnost podepsaného char.
  • Hodnost jakéhokoli typu bez znaménka se rovná hodnosti odpovídajícího celočíselného typu se znaménkem.
  • Hodnost nepodepsaného znaku se rovná hodnosti podepsaného znaku.
  • bool má nejnižší hodnost; jeho pořadí je menší než u podepsaného znaku.
  • char16_t má stejnou pozici jako short int. char32_t má stejné hodnocení jako int. Pro kompilátor g ++ má wchar_t stejnou hodnost jako int.

Integrální propagace

Integral Promotions je Integer Promotions. Neexistuje žádný důvod, proč celé číslo s menším počtem bytů nemůže být reprezentováno celým číslem s větším počtem bytů. Integer Promotions se zabývá vším následujícím:

  • Podepsaný krátký int (dva bajty) lze převést na podepsaný int (čtyři bajty). Nepodepsaný krátký int (dva bajty) lze převést na nepodepsaný int (čtyři bajty). Poznámka: převod krátkého int na dlouhý int nebo dlouhý dlouhý int vede ke ztrátě bajtů úložiště (umístění objektu) a ztrátě paměti. Bool, char16_t, char32_t a wchar_t jsou z této propagace vyňaty (s kompilátorem g ++ mají char32_t a wchar_t stejný počet bajtů).
  • S kompilátorem g ++ lze char16_t typ převést na podepsaný int typ nebo nepodepsaný int typ; typ char32_t lze převést na podepsaný int typ nebo nepodepsaný int typ; a typ wchar_t lze převést na podepsaný nebo nepodepsaný typ int.
  • Typ bool lze převést na typ int. V tomto případě se true stane 1 (čtyři bajty) a false se stane 0 (čtyři bajty). Int může být podepsán nebo podepsán.
  • Celočíselná propagace existuje také pro nezakódovaný typ výčtu - viz dále.

Obvyklé aritmetické převody

Zvažte následující kód:

float f = 2.5;
int i = f;
cout<Tento kód se kompiluje bez udání varování nebo chyby a dává výstup 2, což pravděpodobně není to, co se očekávalo. = je binární operátor, protože bere levý a pravý operand. Zvažte následující kód:

int i1 = 7;
int i2 = 2;
float flt = i1 / i2;
cout<Výstup je 3, ale to je špatně; mělo to být 3.5. Operátor dělení, /, je také binární operátor.

C ++ má obvyklé aritmetické převody, které musí programátor znát, aby se vyhnul chybám v kódování. Obvyklé aritmetické převody na binárních operátorech jsou následující:

  • Pokud je jeden z operandů typu „dlouhý dvojitý“, bude druhý převeden na dlouhý dvojitý.
  • Jinak, pokud je jeden operand zdvojnásoben, druhý bude převeden na dvojnásobek.
  • Jinak, pokud je jeden operand float, druhý bude převeden na float. Ve výše uvedeném kódu je výsledek i1 / i2 oficiálně 2; proto je flt 2. Výsledek binární, /, se použije jako pravý operand na binární operátor, =. Konečná hodnota 2 je tedy float (ne int).

JINÁ PODPORA INTEGRU BY BYLA MÍSTA TAKTO:

  • Pokud jsou oba operandy stejného typu, nedojde k dalšímu převodu.
  • Jinak, pokud jsou oba operandy celočíselné typy se znaménkem nebo oba jsou celočíselné typy bez znaménka, pak bude operand typu s nižším celočíselným hodnocením převeden na typ operandu s vyšším hodnocením.
  • Jinak, pokud je jeden operand podepsán a druhý je bez znaménka, a pokud je typ nepodepsaného operandu větší nebo roven hodnosti podepsaného typu operandu a pokud je hodnota podepsaného operandu větší nebo rovna nule, pak podepsaný operand bude převeden na typ nepodepsaného operandu (s ohledem na rozsah). Pokud je podepsaný operand záporný, kompilátor bude postupovat podle algoritmu a vrátí číslo, které nemusí být pro programátora přijatelné.
  • Jinak, pokud je jeden operand celočíselný typ se znaménkem a druhý je celočíselný typ bez znaménka, a pokud všechny možné hodnoty typu operandu s celočíselným typem bez znaménka lze reprezentovat celočíselným typem se znaménkem, pak bude celočíselný typ bez znaménka být převedeny na typ operandu typu se znaménkem.
  • Jinak by dva operandy (například char a bool) byly převedeny na celočíselný typ bez znaménka.

Propagace s plovoucí desetinnou čárkou

Typy s plovoucí desetinnou čárkou zahrnují „float“, „double“ a „long double.„Typ s plovoucí desetinnou čárkou by měl mít alespoň stejnou přesnost jako jeho předchůdce. Propagace s plovoucí desetinnou čárkou umožňuje převod z float na double nebo z double na long double.

Konverze ukazatele

Ukazatel jednoho typu objektu nelze přiřadit k ukazateli jiného typu objektu. Následující kód nebude kompilován:

int id = 6;
int * intPtr = &id;
float idf = 2.5;
float * floatPtr = &idf;
intPtr = floatPtr; // chyba zde

Nulový ukazatel je ukazatel, jehož hodnota adresy je nula. Nulový ukazatel jednoho typu objektu nelze přiřadit nulovému ukazateli jiného typu objektu. Následující kód nebude kompilován:

int id = 6;
int * intPtr = &id;
intPtr = 0;
float idf = 2.5;
float * floatPtr = &idf;
floatPtr = 0;
intPtr = floatPtr; // chyba zde

Konstantní hodnotu null ukazatele jednoho typu objektu nelze přiřadit konstantní hodnotě null ukazatele jiného typu objektu. Následující kód nebude kompilován:

int id = 6;
int * intPtr = &id;
int * const intPC = 0;
float idf = 2.5;
float * floatPtr = &idf;
float * const floatPC = 0;
intPC = floatPC; // chyba zde

Nulový ukazatel může mít pro svůj typ jinou hodnotu adresy. Následující kód to ilustruje:

float idf = 2.5;
float * floatPtr = 0;
floatPtr = &idf;
cout<<*floatPtr<<'\n';

Výstup je 2.5.

Podle očekávání nelze konstantě nulového ukazatele přiřadit žádnou hodnotu adresy svého typu. Následující kód nebude kompilován:

float idf = 2.5;
float * const floatPC = 0;
floatPC = &idf; // chyba zde

Konstantu nulového ukazatele však lze přiřadit běžnému ukazateli, ale stejného typu (lze to očekávat). Následující kód to ilustruje:

float idf = 2.5;
float * const floatPC = 0;
float * floatPter = &idf;
floatPter = floatPC; //OK
cout << floatPter << '\n';

Výstup je 0.

Dvě hodnoty nulového ukazatele stejného typu jsou stejné (==).

Ukazatel na typ objektu lze přiřadit k ukazateli na void. Následující kód to ilustruje:

float idf = 2.5;
float * floatPtr = &idf;
void * vd;
vd = floatPtr;

Kód se kompiluje bez varování nebo chybové zprávy.

Převod funkce na ukazatel

Ukazatel na funkci, která by nevyvolávala výjimku, lze přiřadit ukazateli na funkci. Následující kód to ilustruje:

#zahrnout
pomocí jmenného prostoru std;
void fn1 () noexcept

cout << "with noexcept" << '\n';

void fn2 ()

// příkazy

void (* func1) () noexcept;
void (* func2) ();
int main ()

func1 = &fn1;
func2 = &fn2;
func2 = &fn1;
func2 ();
návrat 0;

Výstup je bez výjimky.

Booleovské převody

V jazyce C ++ zahrnují entity, které mohou mít za následek hodnotu false, „nula“, „nulový ukazatel“ a „nulový členský ukazatel.„Všechny ostatní entity mají za následek pravdu. Následující kód to ilustruje:

bool a = 0.0; cout << a <<'\n';
float * floatPtr = 0;
bool b = floatPtr; cout << b <<'\n';
bool c = -2.5; cout << c <<'\n';
bool d = +2.5; cout << d <<'\n';

Výstupem je:

0 // pro false
0 // pro false
1 // pro pravdu
1 // pro pravdu

Lvalue, prvalue a xvalue

Zvažte následující kód:

int id = 35;
int & id1 = id;
cout << id1 << '\n';

Výstup je 35. V kódu id a id1 jsou hodnoty, protože identifikují umístění (objekt) v paměti. Výstup 35 je prvočíslo. Libovolný literál, kromě řetězcového literálu, je prvalue. Další prvočísla nejsou tak zřejmá, jako v následujících příkladech. Zvažte následující kód:

int id = 62;
int * ptr = &id;
int * pter;

Ptr je hodnota, protože identifikuje místo (objekt) v paměti. Na druhou stranu pter není lvalue. Pter je ukazatel, ale neidentifikuje žádné místo v paměti (neukazuje na žádný objekt). Pter je tedy prvočíslo.

Zvažte následující kód:

void fn ()

// příkazy

void (* func) () = &fn;
float (* functn) ();

Fn () a (* func) () jsou výrazy lvalue, protože identifikují entitu (funkci) v paměti. Na druhou stranu (* functn) () není výraz lvalue. (* functn) () je ukazatel na funkci, ale neidentifikuje žádnou entitu v paměti (neodkazuje na žádnou funkci v paměti). Takže (* functn) () je výraz první hodnoty.

Nyní zvažte následující kód:

Struct S

int n;
;
S obj;

S je třída a obj je objekt vytvořený z třídy. Obj identifikuje objekt v paměti. Třída je zobecněná jednotka. Takže S ve skutečnosti neidentifikuje žádný objekt v paměti. S je považován za nepojmenovaný objekt. S je také prvočíselný výraz.

Tento článek se zaměřuje na první hodnoty. Prvalue znamená čistou rvalue.

Xvalue

Xvalue znamená Expiring Value. Dočasné hodnoty vyprší. Hodnota lval se může stát hodnotou x. Z první hodnoty se také může stát hodnota x. Tento článek se zaměřuje na první hodnoty. Hodnota x je hodnota l nebo nepojmenovaná reference rvalue, jejíž úložiště lze znovu použít (obvykle proto, že je blízko konce své životnosti). Zvažte následující kód, který funguje:

Struct S

int n;
;
int q = S ().n;

Výraz „int q = S ().n; “ kopíruje jakoukoli hodnotu, kterou n drží, na q. S () je jen prostředek; není to běžně používaný výraz. S () je první hodnota, jejíž použití ji převedlo na hodnotu x.

Převody hodnot na hodnotu r-rvalue

Zvažte následující prohlášení:

int ii = 70;

70 je prvalue (rvalue) a ii je lvalue. Nyní zvažte následující kód:

int ii = 70;
int tt = ii;

Ve druhém prohlášení je ii v situaci prvalue, takže ii se tam stává prvalue. Jinými slovy, kompilátor implicitně převede ii na prvalue. To znamená, že když se hodnota lvalue použije v situaci, kdy implementace očekává první hodnotu, implementace převede hodnotu lvalue na první hodnotu.

Konverze z pole na ukazatel

Zvažte následující kód, který funguje:

char * p;
char q [] = 'a', 'b', 'c';
p = & q [0];
++p;
cout<<*p<<'\n';

Výstup je b. První příkaz je výraz a je ukazatelem na znak. Ale ke kterému znaku prohlášení směřuje? - Žádná postava. Je to tedy prvočíslo a ne hodnota. Druhým příkazem je pole, ve kterém q [] je výraz lvalue. Třetí příkaz změní prvalue, p, na výraz lvalue, který ukazuje na první prvek pole.

Konverze funkce na ukazatel

Zvažte následující program:

#zahrnout
pomocí jmenného prostoru std;
void (* func) ();
void fn ()

// příkazy

int main ()

func = &fn;
návrat 0;

Výraz „void (* func) ();“ je ukazatel na funkci. Ale na kterou funkci výraz směřuje? - Bez funkce. Je to tedy prvočíslo a ne hodnota. Fn () je definice funkce, kde fn je výraz lvalue. V main () „func = &fn;”Změní prvočíslo, func, na výraz lvalue, který ukazuje na funkci, fn ().

Dočasné převody materializace

V C ++ lze první hodnotu převést na xvalue stejného typu. Následující kód to ilustruje:

Struct S

int n;
;
int q = S ().n;

Zde byla první hodnota, S (), převedena na hodnotu x. Jako hodnota x to nebude trvat dlouho - viz další vysvětlení výše.

Konverze kvalifikace

CV kvalifikovaný typ je typ kvalifikovaný vyhrazeným slovem „const“ a / nebo vyhrazeným slovem „volatile“.“

Kvalifikace CV je také hodnocena. Žádná životní kvalifikace není nižší než kvalifikace „const“, což je méně než kvalifikace „const volatile“. Žádná kvalifikace cv není menší než „volatilní“ kvalifikace, což je méně než „volatilní“ kvalifikace. Existují tedy dva proudy hodnocení kvalifikace. Jeden typ může být kvalifikován více než jiný.

Typ s nižší kvalifikací pro cv lze převést na typ s vyšší kvalifikací pro první hodnotu. Oba typy by měly být ukazatelem na cv.

Závěr

Entity C ++ lze převést z jednoho typu na související typ implicitně nebo explicitně. Programátor však musí pochopit, co lze převést a co nelze převést, a do jaké podoby. Konverze může probíhat v následujících doménách: Integrální převody, Konverze s plovoucí desetinnou čárkou, Konverze s plovoucí desetinnou čárkou, Obvyklé aritmetické převody, Konverze ukazatelů, Konverze funkce na ukazatel, Booleovské převody, Konverze L-hodnota na rvalu, Konverze Array-to-Pointer „Konverze mezi funkcemi a ukazateli, dočasné konverze materializace a konverze kvalifikace.

Hry Nejlepší aplikace pro mapování gamepadu pro Linux
Nejlepší aplikace pro mapování gamepadu pro Linux
Pokud rádi hrajete hry na Linuxu s gamepadem místo typického vstupního systému pro klávesnici a myš, máte k dispozici několik užitečných aplikací. Mno...
Hry Užitečné nástroje pro hráče Linuxu
Užitečné nástroje pro hráče Linuxu
Pokud rádi hrajete hry na Linuxu, je pravděpodobné, že jste ke zlepšení herního zážitku použili aplikace a nástroje jako Wine, Lutris a OBS Studio. Kr...
Hry HD remasterované hry pro Linux, které nikdy dříve neměly vydání Linuxu
HD remasterované hry pro Linux, které nikdy dříve neměly vydání Linuxu
Mnoho vývojářů a vydavatelů her přichází s HD remasterem starých her, aby prodloužili životnost franšízy, prosím fanoušky, kteří požadují kompatibilit...