Standardowe konwersje C ++

Standardowe konwersje C ++
Istnieją dwa typy jednostek w C ++, typy podstawowe i typy złożone. Podstawowe typy to typy skalarne. Typy złożone to reszta typów jednostek. Konwersja może odbywać się z jednego typu encji na inny odpowiedni typ. Rozważ następujący program: #include
#włączać
za pomocą przestrzeni nazw Std;
int main ()

int rt1 = sqrt (5);
int rt2 = sqrt (8);
Cout<powrót 0;

Wyjście jest 2, 2, co oznacza, że ​​program zwrócił pierwiastek kwadratowy 5 jako 2, a pierwiastek kwadratowy 8 również jako 2. Tak więc pierwsze dwa stwierdzenia w główny() Funkcja wzbudziła odpowiedzi pierwiastka kwadratowego 5 i pierwiastka kwadratowego 8. W tym artykule nie omawia podłogi ani sufitu w C++. Raczej w tym artykule omówiono konwersję jednego typu C ++ na inny odpowiedni typ C ++; wskazując na wszelkie przybliżenie wartości wykonanej, utrata precyzji lub ograniczenie dodane lub usunięte. Podstawowa znajomość C ++ jest warunkiem zrozumienia tego artykułu.

Treść artykułu

  • Integralne konwersje
  • Przewijające się konwersje
  • Pliczące konwersje integracyjne
  • Ranking konwersji liczb całkowitych
  • Integralne promocje
  • Zwykłe konwersje arytmetyczne
  • Promocja zmiennoprzecinkowa
  • Konwersje wskaźników
  • Funkcja do konwersji wskaźnika
  • Boolean konwersje
  • LValue, PrValue i XValue
  • XValue
  • Konwersje LVALUE-to-Ralue
  • Konwersje tablicy do wskaźnika
  • Konwersje funkcji do punktu
  • Tymczasowe konwersje materializacyjne
  • Konwersje kwalifikacyjne
  • Wniosek

Integralne konwersje

Integralne konwersje to konwersje całkowitowe. Unsigned Liczbuski obejmują „niepodpisany char”, „niepodpisany krótki int”, „unsigned int”, „unsigned long int” i „niepodpisane długie int.„Odpowiednie podpisane liczby całkowite obejmują„ podpisany char ”,„ Short Int ”,„ int ”,„ Long Int ”i„ Long Long Int.„Każdy typ int powinien być utrzymywany w tylu bajtach, co jego poprzednik. W przypadku większości systemów jeden typ jednostki można przekonwertować na odpowiedni typ. Problem występuje podczas konwersji z większego rodzaju zasięgu na mniejszy typ zakresu lub podczas konwersji podpisanej liczby w odpowiednią liczbę niepodpisaną.

Każdy kompilator ma maksymalną wartość, jaką może przyjąć dla krótkiego int. Jeśli liczba wyższa niż ta maksimum, przeznaczona do INT, jest przypisana do krótkiego INT, kompilator będzie śledzić jakiś algorytm i zwróci liczbę w zakresie krótkiego int. Jeśli programista ma szczęście, kompilator ostrzega przed kłopotami z użyciem niewłaściwej konwersji. To samo wyjaśnienie dotyczy konwersji innych typów int.

Użytkownik powinien zapoznać się z dokumentacją kompilatora, aby określić wartości ograniczające dla każdego typu encji.

Jeśli ujemny podpisany krótki numer INT ma zostać przekonwertowany w niepodpisany krótki numer INT, kompilator będzie śledzić jakiś algorytm i zwróci liczbę dodatnią w zakresie niepodpisanego krótkiego int. Tego rodzaju konwersji należy unikać. To samo wyjaśnienie dotyczy konwersji innych typów int.

Każdy numer liczbowy, z wyjątkiem 0, można przekonwertować na boolean true. 0 jest przekonwertowane na boolean false. Poniższy kod to ilustruje:

int a = -27647;
Float B = 2.5;
int c = 0;
bool a1 = a;
Bool B1 = B;
bool c1 = c;
Cout<Cout<Cout<Wyjście to:

1
1
0

1 oznacza prawdziwe, a 0 oznacza fałszywe na wyjściu

Przewijające się konwersje

Typy punktów zmiennoprzecinkowych obejmują „Float”, „Double” i „Long Double.„Typy punktów zmiennoprzecinkowych nie są zgrupowane w podpisane i niepodpisane, jak liczby całkowite. Każdy typ może mieć podpisany lub niepodpisany numer. Typ zmiennoprzecinkowy powinien mieć przynajmniej taką samą precyzję jak jego poprzednik. To znaczy „długa podwójna” powinna mieć równą lub większą precyzję jak „podwójne”, a „podwójne” powinny mieć równą lub większą precyzję w stosunku do „pływaka."

Pamiętaj, że zakres typu zmiennoprzecinkowego nie jest ciągły; jest raczej w małych krokach. Im większa precyzja typu, tym mniejsze kroki i tym większa liczba bajtów do przechowywania liczby. Tak więc, gdy liczba zmiennoprzecinkowa jest konwertowana z niższego typu precyzyjnego na wyższy typ precyzyjny, programista musi zaakceptować fałszywy wzrost precyzji i możliwy wzrost liczby bajtów dla magazynu numeru. Gdy liczba zmiennoprzecinkowa jest konwertowana z wyższego typu precyzyjnego na niższy typ precyzyjny, programista musi zaakceptować utratę precyzji. Jeśli liczba bajtów dla magazynu numerycznych musi zostać zmniejszona, kompilator będzie śledzić jakiś algorytm i zwróci liczbę jako zastępcę (co prawdopodobnie nie jest tym, czego chce programista). Pamiętaj także o problemach z odległości.

Pliczące konwersje integracyjne

Liczba zmiennoprzecinkowa jest konwertowana na liczbę całkowitą poprzez obcięcie części ułamkowej. Poniższy kod to ilustruje:

Float f = 56.953;
int i = f;
Cout<Wyjście jest 56. Zakresy dla pływaka i liczby całkowitej muszą być kompatybilne.

Gdy liczba całkowita jest przekonwertowana na pływak, wartość wyświetlana jako pływak jest taka sama, jak wpisana jako liczba całkowita. Jednak równoważny float może być dokładną wartością lub mieć niewielką różnicę ułamkową, która nie jest wyświetlana. Powodem różnicy ułamkowej jest to, że liczby zmiennoprzecinkowych są reprezentowane w komputerze w małych ułamkowych etapach, a zatem reprezentowanie całkowitej liczby całkowitej byłoby zbiegiem okoliczności. Tak więc, chociaż liczba całkowita wyświetlana jako pływak jest taka sama, jak pisano, wyświetlacz może być przybliżeniem tego, co jest przechowywane.

Ranking konwersji liczb całkowitych

Każdy typ liczb całkowitych ma ranga, która została mu podana. Ten ranking pomaga w konwersji. Ranking jest względny; Rangi nie są na stałym poziomie. Z wyjątkiem Char i podpisanego Char, żadne dwa podpisane liczby całkowite nie mają takiej samej rangi (zakładając, że Char jest podpisany). Niepodpisane typy liczb całkowitych mają taki sam ranking, jak odpowiadające im podpisane typy całkowitej. Ranking jest następujący:

  • Zakładając, że Char został podpisany, a następnie Char i podpisane Char mają tę samą rangę.
  • Ranga podpisanego typu liczb całkowitych jest większa niż ranga podpisanego typu liczb całkowitych mniejszej liczby bajtów pamięci. Tak więc ranga podpisanego długiego INT jest większa niż ranga podpisanego długiego int, co jest większe niż ranga podpisanego INT, co jest większe niż ranga podpisanego krótkiego INT, co jest większe niż ranga podpisanego char.
  • Ranga dowolnego typu liczby całkowitej jest równa ranowi odpowiedniego podpisanego typu liczb całkowitych.
  • Ranga niepodpisanego char jest równa ranga podpisanego char.
  • Bool ma najmniejszą pozycję; jego ranga jest mniejsza niż ranga podpisanego char.
  • char16_t ma taką samą rangę jak krótki int. char32_t ma taki sam ranga jak int. W przypadku kompilatora G ++ WCAR_T ma taką samą rangę jak int.

Integralne promocje

Integralne promocje to promocje całkowitowe. Nie ma powodu, dla którego całkowitej mniejszej liczby bajtów nie może być reprezentowana przez liczbę całkowitą większych bajtów. Promocje liczb całkowitych dotyczy wszystkiego, co następuje:

  • Podpisane krótkie int (dwa bajty) można przekonwertować na podpisany int (cztery bajty). Unsigned Short Int (dwa bajty) można przekonwertować na niepodpisane int (cztery bajty). Uwaga: Przekształcenie krótkiego INT na długą lub długą długą int prowadzi do bajtów do przechowywania (lokalizacji obiektu) i marnotrawstwa pamięci. Bool, Char16_T, Char32_T i Wchar_t są zwolnieni z tej promocji (z kompilatorem G ++, Char32_T i Wchar_t mają tę samą liczbę bajtów).
  • Za pomocą kompilatora G ++ typ Char16_T można przekonwertować na podpisany typ int lub niepodpisany typ int; Typ char32_t można przekonwertować na podpisany typ int lub niepodpisany typ int; a typ Wchar_t można przekonwertować na podpisany lub niepodpisany typ int.
  • Typ Bool można przekonwertować na typ int. W tym przypadku True staje się 1 (cztery bajty), a Fałsz staje się 0 (cztery bajty). INT może zostać podpisany lub podpisany.
  • Istnieje również promocja liczb całkowity.

Zwykłe konwersje arytmetyczne

Rozważ następujący kod:

float f = 2.5;
int i = f;
Cout<Kod kompikuje się bez wskazania żadnego ostrzeżenia lub błędu, co daje wyjście 2, co prawdopodobnie nie było oczekiwane. = jest operatorem binarnym, ponieważ zajmuje lewy i prawy operand. Rozważ następujący kod:

int i1 = 7;
int i2 = 2;
float flt = i1 / i2;
Cout<Wyjście jest 3, Ale to jest złe; to miało być 3.5. Operator działu, /, jest również operatorem binarnym.

C ++ ma zwykle konwersje arytmetyczne, które programista musi wiedzieć, aby uniknąć błędów w kodowaniu. Zwykłe konwersje arytmetyczne na operatorach binarnych są następujące:

  • Jeśli którykolwiek operand jest typu „długi podwójny”, drugi zostanie przekonwertowany na długie podwójne.
  • W przeciwnym razie, jeśli którykolwiek operand jest podwójny, drugi zostanie przekonwertowany na podwójny.
  • W przeciwnym razie, jeśli którykolwiek operand jest pływający, drugi zostanie przekonwertowany na pływak. W powyższym kodzie wynikiem I1/i2 jest oficjalnie 2; Dlatego FLT ma 2. Wynik binarny, /, jest stosowany jako właściwy operand do operatora binarnego, =. Tak więc końcowa wartość 2 to pływak (nie INT).

W przeciwnym razie promocja liczb całkowita miałaby miejsce w następujący sposób:

  • Jeśli oba operandy są tego samego typu, to nie ma dalszej konwersji.
  • W przeciwnym razie, jeśli oba operandy są podpisane typy liczb całkowitych lub oba są typami liczb całkowitych niepodpisanych, wówczas operand typu o niższej liczbie całkowity.
  • W przeciwnym razie, jeśli jeden operand jest podpisany, a drugi jest niepodpisany, a jeśli niepodpisany typ operand jest większy lub równy ranowi podpisanego typu operandu, a jeśli wartość podpisanego operandu jest większa lub równa zero, wówczas zero, to Podpisany operand zostanie przekonwertowany na niepodpisany typ operand (z uwzględnieniem zakresu). Jeśli podpisany operand jest ujemny, wówczas kompilator będzie śledzić algorytm i zwróci numer, który może nie być dopuszczalny do programisty.
  • W przeciwnym razie, jeśli jeden operand jest podpisanym typem liczb całkowitych, a drugi jest niepodpisanym typem liczb całkowity być przekonwertowanym na rodzaj operandu podpisanego typu liczb całkowitych.
  • W przeciwnym razie dwa operandy (na przykład char i bool) zostaną przekonwertowane na niepodpisaną liczbę całkowitą.

Promocja zmiennoprzecinkowa

Typy punktów zmiennoprzecinkowych obejmują „Float”, „Double” i „Long Double.„Typ zmiennoprzecinkowy powinien mieć co najmniej taką samą precyzję jak jego poprzednik. Promocja zmiennoprzecinkowa pozwala na konwersję z pływaków do podwójnej lub z podwójnej do długiego do długiego.

Konwersje wskaźników

Wskaźnika jednego typu obiektu nie można przypisać do wskaźnika innego typu obiektu. Poniższy kod nie skompiluje:

int id = 6;
int* intptr = &id;
float idf = 2.5;
float* floatptr = &idf;
intptr = floatptr; // Błąd tutaj

Wskaźnik zerowy to wskaźnik, którego wartość adresu wynosi zero. Nie można przypisać wskaźnika zerowego jednego obiektu do wskaźnika zerowego innego typu obiektu. Poniższy kod nie skompiluje:

int id = 6;
int* intptr = &id;
intptr = 0;
float idf = 2.5;
float* floatptr = &idf;
floatptr = 0;
intptr = floatptr; // Błąd tutaj

Nie można przypisać wskaźnika zerowego jednego typu obiektu do wskaźnika zerowego, stał. Poniższy kod nie skompiluje:

int id = 6;
int* intptr = &id;
int* const intpc = 0;
float idf = 2.5;
float* floatptr = &idf;
float* const floatpc = 0;
intpc = floatpc; // Błąd tutaj

Wskaźnik zerowy może otrzymać inną wartość adresu dla swojego typu. Poniższy kod to ilustruje:

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

Wyjście jest 2.5.

Zgodnie z oczekiwaniami, stałą wskaźnika zerowego nie można przypisać żadnej wartości adresu tego typu. Poniższy kod nie skompiluje:

float idf = 2.5;
float* const floatpc = 0;
floatpc = &idf; // Błąd tutaj

Jednak stałą wskaźnika zerowego można przypisać do zwykłego wskaźnika, ale tego samego typu (należy się tego spodziewać). Poniższy kod to ilustruje:

float idf = 2.5;
float* const floatpc = 0;
float* floatpter = &idf;
floatPter = floatpc; //OK
Cout << floatPter << '\n';

Wyjście jest 0.

Dwie wartości zerowych wskaźników tego samego typu Porównaj (==) równe.

Wskaźnik do typu obiektu można przypisać do wskaźnika do pustki. Poniższy kod to ilustruje:

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

Kod kompikuje się bez komunikatu ostrzegawczego lub błędu.

Funkcja do konwersji wskaźnika

Wskaźnik do funkcji, która nie rzuciłaby wyjątku, można przypisać do wskaźnika do funkcjonowania. Poniższy kod to ilustruje:

#włączać
za pomocą przestrzeni nazw Std;
void fn1 () no -except

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

void fn2 ()

//sprawozdania

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

func1 = &fn1;
func2 = &fn2;
func2 = &fn1;
func2 ();
powrót 0;

Wyjście jest bez z wyjątkiem.

Boolean konwersje

W C ++ jednostki, które mogą skutkować fałszem, obejmują „zero”, „null wskaźnik” i „null wskaźnik członka.„Wszystkie inne podmioty powodują prawdziwe. Poniższy kod 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';

Wyjście to:

0 // dla fałszu
0 // dla fałszu
1 // dla prawda
1 // dla prawda

LValue, PrValue i XValue

Rozważ następujący kod:

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

Wyjście jest 35. W kodzie ID i ID1 są LVALES, ponieważ identyfikują lokalizację (obiekt) w pamięci. Wyjście 35 jest pralelem. Wszelkie dosłowne, z wyjątkiem dosłownego sznurka, jest pralue. Inne praledy nie są tak oczywiste, jak w następujących przykładach. Rozważ następujący kod:

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

PTR to LValue, ponieważ identyfikuje lokalizację (obiekt) w pamięci. Z drugiej strony Pter nie jest LValue. Pter jest wskaźnikiem, ale nie identyfikuje żadnej lokalizacji w pamięci (nie wskazuje na żaden obiekt). Więc Pter jest pralelem.

Rozważ następujący kod:

void fn ()

//sprawozdania

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

Fn () i (*func) () to wyrażenia LVALUE, ponieważ identyfikują one (funkcję) w pamięci. Z drugiej strony (*functn) () nie jest wyrażeniem LValue. (*functn) () jest wskaźnikiem funkcji, ale nie identyfikuje żadnej jednostki w pamięci (nie wskazuje na żadną funkcję w pamięci). Tak więc (*functn) () jest wyrażeniem pralue.

Teraz rozważ następujący kod:

struktura s

int n;
;
S Obj;

S jest klasą, a OBJ to obiekt utworzony z klasy. OBJ identyfikuje obiekt w pamięci. Klasa to jednostka uogólniona. Tak naprawdę nie identyfikuje żadnego obiektu w pamięci. Mówi się, że jest nienazwanym obiektem. S jest również wyrażeniem pralera.

Ten artykuł koncentruje się na pralelach. Prvalue oznacza czystą relację.

XValue

XValue oznacza wygasną wartość. Wartości tymczasowe wygasają wartości. LValue może stać się wartością X. Pralela może również stać się xalecem. Ten artykuł koncentruje się na pralelach. WVALUE to lValue lub nienazwane odniesienie RValue, którego przechowywanie można ponownie wykorzystać (zwykle dlatego, że znajduje się pod koniec swojego życia). Rozważ następujący kod, który działa:

struktura s

int n;
;
int q = s ().N;

Wyrażenie „int q = s ().N;" kopiuje jakąkolwiek wartość n utrzymuje Q. S () to tylko sposób; Nie jest to regularnie używane wyrażenie. S () to pralera, której użycie przekonwertowało go na wartość xValue.

Konwersje LVALUE-to-Ralue

Rozważ następujące stwierdzenie:

int II = 70;

70 to pralue (RValue), a II to lowca. Teraz rozważ następujący kod:

int II = 70;
int tt = ii;

W drugim stwierdzeniu II znajduje się w sytuacji pralela, więc ii staje się tam. Innymi słowy, kompilator przekształca II w niejawnie. To znaczy, gdy lowca jest używana w sytuacji, w której implementacja oczekuje pralela, implementacja przekształca lValue na pralera.

Konwersje tablicy do wskaźnika

Rozważ następujący kod, który działa:

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

Wyjście jest B. Pierwsze stwierdzenie jest wyrażeniem i jest wskaźnikiem postaci. Ale na który postać jest wskazującym? - Brak charakteru. Jest to więc pralera, a nie lValue. Drugie stwierdzenie to tablica, w której Q [] jest wyrażeniem LValue. Trzecie stwierdzenie przekształca pralue, p, w wyrażenie LValue, które wskazuje na pierwszy element tablicy.

Konwersje funkcji do punktu

Rozważ następujący program:

#włączać
za pomocą przestrzeni nazw Std;
void (*func) ();
void fn ()

//sprawozdania

int main ()

func = &fn;
powrót 0;

Wyrażenie „void (*func) ();” jest wskaźnikiem funkcji. Ale do której funkcji jest wyrażenie wskazującym? - Brak funkcji. Jest to więc pralera, a nie lValue. Fn () jest definicją funkcji, w której FN jest wyrażeniem LValue. W Main (), „func = &fn;„Zmienia pralue, FUNC, w wyrażenie LValue, które wskazuje na funkcję, fn ().

Tymczasowe konwersje materializacyjne

W C ++ pralera można przekonwertować na XValue tego samego typu. Poniższy kod to ilustruje:

struktura s

int n;
;
int q = s ().N;

Tutaj PrValue, s (), został przekonwertowany na xvalue. Jako xvalue nie trwałoby to długo - zobacz więcej wyjaśnień powyżej.

Konwersje kwalifikacyjne

Typ kwalifikowanym przez CV jest typem kwalifikowanym przez zarezerwowane słowo „const” i/lub zarezerwowane słowo „niestabilne."

Kwalifikacja CV jest również rankingowa. Żadna kwalifikacja CV nie jest mniejsza niż kwalifikacja „const”, która jest mniejsza niż „const niestabilna” kwalifikacje. Żadne kwalifikacja CV nie jest niższa niż „niestabilna” kwalifikacja, która jest mniejsza niż „niestabilna” kwalifikacja. Istnieją więc dwa strumienie rankingu kwalifikacji. Jeden typ może być bardziej kwalifikowany CV niż inny.

Niższy typ CV-kwalifikowany CV można przekonwertować na bardziej kwalifikowany przez CV typu PrValue. Oba typy powinny być wskaźnikiem do CV.

Wniosek

Podmioty C ++ można przeliczyć z jednego typu na powiązany typ lub jawnie. Jednak programista musi zrozumieć, co można przekonwertować, a czego nie można przekonwertować, i w jakiej formie. Konwersja może odbywać się w następujących domenach: Konwersje integralne, konwersje zmiennoprzecinkowe, konwersje pływające-integracyjne, zwykłe konwersje arytmetyczne, konwersje wskaźników, funkcja konwersji wskaźnika, konwersje boolec , Konwersje funkcjonalne do punktu, tymczasowe konwersje materializacyjne i konwersje kwalifikacyjne.