C++

C++ standaardconversies

C++ standaardconversies
Er zijn twee entiteitstypen in C++, de fundamentele typen en de samengestelde typen. De fundamentele typen zijn de scalaire typen. De samengestelde typen zijn de rest van de entiteitstypen. Conversie kan plaatsvinden van het ene entiteitstype naar een ander geschikt type. Denk aan het volgende programma:

#include
#include
namespace std; gebruiken;
int hoofd()

int rt1 = sqrt(5);
int rt2 = sqrt(8);
cout<retourneer 0;

De uitvoer is: 2, 2, wat betekent dat het programma de vierkantswortel van 5 heeft teruggegeven als 2 en de vierkantswortel van 8 ook als 2. Dus de eerste twee uitspraken in de hoofd() functie hebben de antwoorden van de vierkantswortel van 5 en de vierkantswortel van 8 . gevloerd. Dit artikel gaat niet over vloeren of plafonds in C++. In plaats daarvan bespreekt dit artikel de conversie van het ene C++-type naar een ander geschikt C++-type; met vermelding van enige benadering in gemaakte waarde, verlies van precisie of toegevoegde of verwijderde beperking cons. Basiskennis van C++ is een vereiste om dit artikel te begrijpen.

Artikel Inhoud

  • Integrale conversies
  • Drijvende-komma-conversies
  • Zwevende integrale conversies
  • Gehele conversierangschikking
  • Integrale promoties
  • Gebruikelijke rekenkundige conversies
  • Floating-point-promotie
  • Aanwijzerconversies
  • Functie naar aanwijzer conversies
  • Booleaanse conversies
  • Lwaarde, prwaarde en xwaarde
  • Xwaarde
  • Lvalue-naar-rvalu-conversies
  • Array-naar-pointer-conversies
  • Functie-naar-wijzer conversies
  • Tijdelijke materialisatieconversies
  • Kwalificatieconversies
  • Conclusie

Integrale conversies

Integrale conversies zijn integer conversies. Niet-ondertekende gehele getallen omvatten "unsigned char", "unsigned short int", "unsigned int", "unsigned long int" en "unsigned long long int.” De corresponderende getekende gehele getallen omvatten “signed char”, “short int”, “int”, “long int” en “long long int."Elk int-type moet in evenveel bytes worden bewaard als zijn voorganger. Voor de meeste systemen kan één entiteitstype zonder problemen worden geconverteerd naar een overeenkomstig type. Het probleem doet zich voor bij het converteren van een groter bereiktype naar een kleiner bereiktype, of bij het converteren van een ondertekend nummer naar een overeenkomstig niet-ondertekend nummer.

Elke compiler heeft een maximale waarde die kan worden gebruikt voor de korte int. Als een getal hoger dan dat maximum, bedoeld voor een int, wordt toegewezen aan de korte int, zal de compiler een algoritme volgen en een getal retourneren binnen het bereik van de korte int. Als de programmeur geluk heeft, zal de compiler waarschuwen voor problemen met het gebruik van ongepaste conversie. Dezelfde uitleg is van toepassing op conversies van andere int-typen.

De gebruiker moet de documentatie van de compiler raadplegen om de grenswaarden voor elk entiteitstype te bepalen.

Als een negatief ondertekend short int-nummer moet worden omgezet in een unsigned short int-nummer, zal de compiler een algoritme volgen en een positief getal retourneren binnen het bereik van de unsigned short int. Dit soort conversie moet worden vermeden. Dezelfde uitleg is van toepassing op conversies van andere int-typen.

Elk geheel getal, behalve 0, kan worden geconverteerd naar Booleaans waar. 0 wordt geconverteerd naar Booleaans false. De volgende code illustreert dit:

int a = -27647;
vlotter b = 2.5;
intc = 0;
bool a1 = een;
bool b1 = b;
bool cl = c;
cout<cout<cout<De uitvoer is:

1 voor waar
1 voor waar
0 voor onwaar

Drijvende-kommaconversies

Typen met drijvende komma zijn onder meer 'zwevend', 'dubbel' en 'lang dubbel'.Typen met drijvende komma worden niet gegroepeerd in ondertekend en niet-ondertekend, zoals gehele getallen. Elk type kan een ondertekend of niet-ondertekend nummer hebben. Een type met drijvende komma moet minstens dezelfde precisie hebben als zijn voorganger. Dat wil zeggen, "long double" moet dezelfde of grotere precisie hebben als "double" en "double" moet dezelfde of grotere precisie hebben als "float".”

Onthoud dat het bereik van een type met drijvende komma niet continu is; het is eerder in kleine stappen. Hoe groter de precisie van het type, hoe kleiner de stappen en hoe groter het aantal bytes om het nummer op te slaan. Dus wanneer een getal met drijvende komma wordt geconverteerd van een type met lagere precisie naar een type met hogere precisie, moet de programmeur een valse toename in precisie accepteren en een mogelijke toename van het aantal bytes voor nummeropslag. Wanneer een getal met drijvende komma wordt geconverteerd van een type met hogere precisie naar een type met lagere precisie, moet de programmeur een verlies in precisie accepteren. Als het aantal bytes voor het opslaan van nummers moet worden verminderd, zal de compiler een algoritme volgen en een getal retourneren als vervanging (wat waarschijnlijk niet is wat de programmeur wil). Houd ook rekening met problemen buiten het bereik.

Zwevende integrale conversies

Een getal met drijvende komma wordt omgezet in een geheel getal door het fractionele deel af te kappen. De volgende code illustreert dit:

vlotter f = 56.953;
int ik = f;
cout<De uitvoer is: 56. De bereiken voor de float en integer moeten compatibel zijn.

Wanneer een geheel getal wordt geconverteerd naar een float, is de waarde die wordt weergegeven als een float dezelfde als die is ingetypt als een geheel getal. Het float-equivalent kan echter de exacte waarde zijn of een klein fractioneel verschil hebben dat niet wordt weergegeven. De reden voor het fractionele verschil is dat getallen met drijvende komma in de computer worden weergegeven in kleine fractionele stappen, en dus het exact weergeven van het gehele getal zou toeval zijn. Dus, hoewel het gehele getal dat wordt weergegeven als een float hetzelfde is als het werd getypt, kan de weergave een benadering zijn van wat is opgeslagen.

Gehele conversierangschikking

Elk integer type heeft een rang die eraan is gegeven. Deze rangschikking helpt bij de conversie. De rangorde is relatief; de rangen zijn niet op vaste niveaus. Behalve voor char en ondertekende char, hebben geen twee ondertekende gehele getallen dezelfde rang (ervan uitgaande dat char is ondertekend). Niet-ondertekende integer-typen hebben dezelfde rangorde als hun corresponderende ondertekende integer-typen. De rangschikking is als volgt:

  • Ervan uitgaande dat char is ondertekend, hebben char en ondertekende char dezelfde rang.
  • De rangorde van een type geheel getal met teken is groter dan de rang van een type geheel getal met teken van een kleiner aantal opslagbytes. Dus de rangorde van ondertekende lange lange int is groter dan de rangorde van ondertekende lange int, die groter is dan de rang van ondertekende int, die groter is dan de rangorde van ondertekende korte int, die groter is dan de rang van ondertekende char.
  • De rangorde van elk type geheel getal zonder teken is gelijk aan de rang van het overeenkomstige type geheel getal met teken.
  • De rang van niet-ondertekende char is gelijk aan de rang van ondertekende char.
  • bool heeft de minste rang; zijn rang is minder dan die van ondertekende char.
  • char16_t heeft dezelfde rang als de korte int. char32_t heeft dezelfde rang als de int. Voor de g++-compiler heeft wchar_t dezelfde rang als de int.

Integrale promoties

Integrale promoties is gehele promoties. Er is geen reden waarom een ​​geheel getal van minder bytes niet kan worden weergegeven door een geheel getal van meer bytes. Integer Promotions behandelt alles wat volgt:

  • Een ondertekende korte int (twee bytes) kan worden geconverteerd naar een ondertekende int (vier bytes). Een niet-ondertekende korte int (twee bytes) kan worden geconverteerd naar een niet-ondertekende int (vier bytes). Opmerking: het converteren van een korte int naar een lange int of een lange lange int leidt tot een verspilling van opslag (objectlocatie) bytes en een verspilling van geheugen. Bool, char16_t, char32_t en wchar_t zijn vrijgesteld van deze promotie (met de g++ compiler hebben char32_t en wchar_t hetzelfde aantal bytes).
  • Met de g++-compiler kan een char16_t-type worden geconverteerd naar een ondertekend int-type of een niet-ondertekend int-type; een char32_t-type kan worden geconverteerd naar een ondertekend int-type of een niet-ondertekend int-type; en een wchar_t-type kan worden geconverteerd naar een ondertekend of niet-ondertekend int-type.
  • Een bool-type kan worden geconverteerd naar een int-type. In dit geval wordt waar 1 (vier bytes) en onwaar wordt 0 (vier bytes). Int kan worden ondertekend of ondertekend.
  • Integer-promotie bestaat ook voor een opsommingstype zonder scope - zie later.

Gebruikelijke rekenkundige conversies

Beschouw de volgende code:

vlotter f = 2.5;
int ik = f;
cout<De code wordt gecompileerd zonder enige waarschuwing of fout aan te geven, en geeft de uitvoer van 2, wat waarschijnlijk niet is wat verwacht werd. = is een binaire operator omdat er een linker en rechter operand nodig is. Beschouw de volgende code:

int i1 = 7;
int i2 = 2;
vlotter flt = i1 / i2;
cout<De uitvoer is: 3, maar dit is verkeerd; het was bedoeld als 3.5. De delingsoperator, /, is ook een binaire operator.

C++ heeft gebruikelijke rekenkundige conversies die de programmeur moet kennen om fouten bij het coderen te voorkomen avoid. De gebruikelijke rekenkundige conversies op binaire operatoren zijn als volgt:

  • Als een van de operanden van het type "long double" is, wordt de andere geconverteerd naar long double.
  • Anders, als een van de operanden dubbel is, wordt de andere geconverteerd naar dubbel.
  • Anders, als een van de operanden float is, wordt de andere geconverteerd naar float. In de bovenstaande code is het resultaat van i1/i2 officieel 2; daarom is flt 2. Het resultaat van de binaire, /, wordt toegepast als de juiste operand op de binaire operator, =. Dus de uiteindelijke waarde van 2 is een float (geen int).

ANDERS ZOU DE PROMOTIE OP HET GEHELE GEHALTE ALS VOLGT PLAATSVINDEN:

  • Als beide operanden van hetzelfde type zijn, vindt er geen verdere conversie plaats.
  • Anders, als beide operanden integer-types met teken zijn of beide integer-types zonder teken zijn, wordt de operand van het type met de lagere integer-rang geconverteerd naar het type van de operand met de hogere rang.
  • Anders, als de ene operand is ondertekend en de andere niet is ondertekend, en als het niet-ondertekende operandtype groter is dan of gelijk is aan de rangorde van het ondertekende operandtype, en als de waarde van de ondertekende operand groter is dan of gelijk is aan nul, dan de ondertekende operand wordt geconverteerd naar het niet-ondertekende operandtype (waarbij rekening wordt gehouden met het bereik). Als de ondertekende operand negatief is, zal de compiler een algoritme volgen en een getal retourneren dat mogelijk niet acceptabel is voor de programmeur.
  • Anders, als de ene operand een geheel getal met teken is en de andere een geheel getal zonder teken, en als alle mogelijke waarden van het type van de operand met het type geheel getal zonder teken kunnen worden weergegeven door het type geheel getal met teken, dan zal het type geheel getal zonder teken worden geconverteerd naar het type van de operand van het ondertekende integer-type.
  • Anders zouden de twee operanden (bijvoorbeeld een char en een bool) worden geconverteerd naar het niet-ondertekende integer-type.

Floating-point-promotie

Typen met drijvende komma zijn onder meer 'zwevend', 'dubbel' en 'lang dubbel'.” Een floating-point type moet minstens dezelfde precisie hebben als zijn voorganger. Floating-point-promotie maakt conversie mogelijk van float naar double of van double naar long double.

Aanwijzerconversies

Een aanwijzer van het ene objecttype kan niet worden toegewezen aan een aanwijzer van een ander objecttype. De volgende code wordt niet gecompileerd:

int-id = 6;
int* intPtr = &id;
float idf = 2.5;
float* floatPtr = &idf;
intPtr = floatPtr; // fout hier

Een null-pointer is een pointer waarvan de adreswaarde nul is. Een null-pointer van het ene objecttype kan niet worden toegewezen aan een null-pointer van een ander objecttype. De volgende code wordt niet gecompileerd:

int-id = 6;
int* intPtr = &id;
intPtr = 0;
float idf = 2.5;
float* floatPtr = &idf;
floatPtr = 0;
intPtr = floatPtr; // fout hier

Een null pointer const van een objecttype kan niet worden toegewezen aan een null pointer const van een ander objecttype. De volgende code wordt niet gecompileerd:

int-id = 6;
int* intPtr = &id;
int* const intPC = 0;
float idf = 2.5;
float* floatPtr = &idf;
float* const floatPC = 0;
intPC = floatPC; // fout hier

Een null-pointer kan een andere adreswaarde krijgen voor zijn type. De volgende code illustreert dit:

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

De uitvoer is: 2.5.

Zoals verwacht, kan aan een nul-aanwijzerconstante geen adreswaarde van zijn type worden toegewezen. De volgende code wordt niet gecompileerd:

float idf = 2.5;
float* const floatPC = 0;
floatPC = &idf; //fout hier

Aan een gewone pointer kan echter een null-pointerconstante worden toegewezen, maar van hetzelfde type (dit is te verwachten). De volgende code illustreert dit:

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

De uitvoer is: 0.

Twee null-pointerwaarden van hetzelfde type vergelijken (==) gelijk.

Een pointer naar een objecttype kan worden toegewezen aan een pointer to void. De volgende code illustreert dit:

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

De code compileert zonder waarschuwing of foutmelding warning.

Functie naar aanwijzer conversies

Een aanwijzer naar een functie die geen uitzondering zou veroorzaken, kan worden toegewezen aan een aanwijzer naar functie. De volgende code illustreert dit:

#include
namespace std; gebruiken;
void fn1() neebehalve

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

ongeldig fn2()

//verklaringen

void (*func1)() neebehalve;
ongeldig (*func2)();
int hoofd()

func1 = &fn1;
func2 = &fn2;
func2 = &fn1;
func2();
retourneer 0;

De uitvoer is: zonder uitzondering.

Booleaanse conversies

In C++ zijn entiteiten die in false kunnen resulteren, onder meer "nul", "null pointer" en "null member pointer.” Alle andere entiteiten resulteren in true. De volgende code illustreert dit:

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';

De uitvoer is:

0 //voor false
0 //voor false
1 //voor waar
1 //voor waar

Lwaarde, prwaarde en xwaarde

Beschouw de volgende code:

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

De uitvoer is: 35. In de code zijn id en id1 lwaarden omdat ze een locatie (object) in het geheugen identificeren. De uitvoer 35 is een prwaardevalu. Elke letterlijke waarde, behalve een letterlijke tekenreeks, is een prwaarde. Andere pr-waarden zijn niet zo voor de hand liggend, zoals in de voorbeelden die volgen. Beschouw de volgende code:

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

Ptr is een lwaarde omdat het een locatie (object) in het geheugen identificeert. Aan de andere kant is pter geen waarde. Pter is een aanwijzer, maar het identificeert geen enkele locatie in het geheugen (het wijst niet naar een object). Dus pter is een prwaarde.

Beschouw de volgende code:

ongeldig fn()

//verklaringen

leegte (*func)() = &fn;
zweven (*functn)();

Fn() en (*func)() zijn lvalue-expressies omdat ze een entiteit (functie) in het geheugen identificeren. Aan de andere kant is (*functn)() geen lvalue-expressie. (*functn)() is een aanwijzer naar een functie, maar het identificeert geen enkele entiteit in het geheugen (het verwijst niet naar een functie in het geheugen). Dus (*functn)() is een prwaarde-expressie.

Overweeg nu de volgende code:

struct S

int n;
;
zo obj;

S is een klasse en obj is een object dat is geïnstantieerd vanuit de klasse. Obj identificeert een object in het geheugen. Een klasse is een gegeneraliseerde eenheid. Dus S identificeert niet echt een object in het geheugen. Er wordt gezegd dat S een niet nader genoemd object is. S is ook een prwaarde-expressie.

De focus van dit artikel ligt op prvalues. Prvalue betekent pure rwaarde.

Xwaarde

Xvalue staat voor Expiring Value. Tijdelijke waarden zijn verlopende waarden. Een lwaarde kan een xwaarde worden. Een prwaarde kan ook een xwaarde worden. De focus van dit artikel ligt op prvalues. Een xvalue is een lvalue of een naamloze rvalue-referentie waarvan de opslag kan worden hergebruikt (meestal omdat deze bijna aan het einde van zijn levensduur is). Overweeg de volgende code die werkt:

struct S

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

De uitdrukking "int q = S().nt;” kopieert de waarde van n naar q. S() is slechts een middel; het is geen regelmatig gebruikte uitdrukking. S() is een prwaarde waarvan het gebruik het heeft omgezet in een xwaarde.

Lvalue-naar-rvalu-conversies

Denk aan de volgende stelling:

intii = 70;

70 is een prvalue (rvalue) en ii is een lvalue. Overweeg nu de volgende code:

intii = 70;
int tt = ii;

In de tweede verklaring bevindt ii zich in de situatie van een pr-waarde, dus ii wordt daar een pr-waarde. Met andere woorden, de compiler converteert ii impliciet naar een prwaardevalu. Dat wil zeggen, wanneer een l-waarde wordt gebruikt in een situatie waarin de implementatie een pr-waarde verwacht, converteert de implementatie de l-waarde naar een pr-waarde.

Array-naar-pointer-conversies

Overweeg de volgende code die werkt:

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

De uitvoer is: b. De eerste instructie is een uitdrukking en is een verwijzing naar een teken. Maar naar welk karakter verwijst de verklaring?? - Geen karakter. Het is dus een pr-waarde en geen l-waarde. De tweede instructie is een array waarin q[] een lvalue-expressie is. De derde instructie verandert de prvalue, p, in een lvalue-expressie, die verwijst naar het eerste element van de array.

Functie-naar-wijzer conversies

Denk aan het volgende programma:

#include
namespace std; gebruiken;
ongeldig (*func)();
ongeldig fn()

//verklaringen

int hoofd()

func = &fn;
retourneer 0;

De uitdrukking "void (*func)();" is een aanwijzer naar een functie. Maar naar welke functie verwijst de uitdrukking?? - Geen functie. Het is dus een pr-waarde en geen l-waarde. Fn() is een functiedefinitie, waarbij fn een lwaarde-expressie is. In main(), “func = &fn;” verandert de prvalue, func, in een lvalue-expressie die verwijst naar de functie fn().

Tijdelijke materialisatieconversies

In C++ kan een prwaarde worden geconverteerd naar een xwaarde van hetzelfde type. De volgende code illustreert dit:

struct S

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

Hier is de prwaarde, S(), geconverteerd naar een xwaarde. Als x-waarde zou het niet lang duren - zie meer uitleg hierboven.

Kwalificatieconversies

Een cv-gekwalificeerd type is een type dat wordt gekwalificeerd door het gereserveerde woord 'const' en/of het gereserveerde woord 'vluchtig'.”

Cv-kwalificatie wordt ook gerangschikt. Geen enkele cv-kwalificatie is minder dan de kwalificatie 'const', wat minder is dan de kwalificatie 'const vluchtig'. Geen enkele cv-kwalificatie is minder dan een "vluchtige" kwalificatie, wat minder is dan een "const-vluchtige" kwalificatie. Er zijn dus twee stromen van kwalificatierangschikking. Het ene type kan meer cv-gekwalificeerd zijn dan het andere.

Een cv-gekwalificeerd type met een lagere pr-waarde kan worden geconverteerd naar een type met meer cv-gekwalificeerd pr-waarde. Beide typen moeten pointer-to-cv zijn.

Conclusie

C++-entiteiten kunnen impliciet of expliciet van het ene type naar een gerelateerd type worden geconverteerd. De programmeur moet echter begrijpen wat kan worden omgezet en wat niet kan worden omgezet, en in welke vorm. Conversie kan plaatsvinden in de volgende domeinen: Integrale Conversies, Floating-Point Conversies, Floating-Integrale Conversies, Gebruikelijke Rekenkundige Conversies, Pointer Conversies, Functie naar Pointer Conversies, Boolean Conversies, Lvalue-naar-rvalue Conversies, Array-naar-Pointer Conversies , conversies van functie naar pointer, conversies van tijdelijke materialisatie en kwalificatieconversies.

OSD-overlay tonen in Linux-apps en -games op volledig scherm
Het spelen van games op volledig scherm of het gebruik van apps in de modus volledig scherm zonder afleiding kan u afsnijden van relevante systeeminfo...
Top 5 Game Capture-kaarten
We hebben allemaal gezien en genoten van streaming gameplays op YouTube. PewDiePie, Jakesepticye en Markiplier zijn slechts enkele van de beste gamers...
Hoe een spel op Linux te ontwikkelen
Tien jaar geleden zouden niet veel Linux-gebruikers voorspellen dat hun favoriete besturingssysteem ooit een populair spelplatform voor commerciële vi...