#include
namespace std; gebruiken;
int hoofd()
int rt1 = sqrt(5);
int rt2 = sqrt(8);
cout<
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<
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<
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:
#includenamespace 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 false0 //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 Sint 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 Sint 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:
#includenamespace 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 Sint 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.