C ++

Стандартни конверсии на C ++

Стандартни конверсии на C ++
В C ++ има два типа обекти, основните типове и съставните типове. Основните типове са скаларните типове. Типовете съединения са останалите типове обекти. Преобразуването може да се извърши от един тип обект в друг подходящ тип. Обмислете следната програма:

#include
#include
използване на пространство от имена std;
int main ()

int rt1 = sqrt (5);
int rt2 = sqrt (8);
Cout<връщане 0;

Изходът е 2, 2, което означава, че програмата е върнала квадратния корен от 5 като 2 и квадратния корен от 8 също като 2. И така, първите две твърдения в главен () функцията са поставили отговорите на квадратния корен от 5 и квадратния корен от 8. Тази статия не обсъжда подови настилки или таван в C++. По-скоро тази статия обсъжда преобразуването на един тип C ++ в друг подходящ тип C ++; посочващ всяко приближение на направената стойност, загуба на прецизност или ограничение, добавено или премахнато. Базовото познание на C ++ е предпоставка за разбиране на тази статия.

Съдържание на статията

  • Интегрални конверсии
  • Преобразувания с плаваща запетая
  • Плаващи-интегрални конверсии
  • Цялостно класиране на преобразуването
  • Интегрални промоции
  • Обичайни аритметични преобразувания
  • Промоция с плаваща запетая
  • Преобразувания на показалеца
  • Функция за преобразуване на показалеца
  • Булеви преобразувания
  • Lvalue, prvalue и xvalue
  • Xvalue
  • Преобразувания Lvalue към rvalue
  • Преобразувания от масив към указател
  • Преобразувания от функция към указател
  • Временни конверсии на материализация
  • Квалификационни конверсии
  • Заключение

Интегрални конверсии

Интегралните преобразувания са целочислени преобразувания. Неподписаните цели числа включват „неподписан знак“, „неподписан кратък int“, „неподписан int“, „неподписан дълъг int“ и „неподписан дълъг дълъг int“.“Съответните подписани цели числа включват„ подписан знак “,„ къс int “,„ int “,„ дълъг int “и„ дълъг дълъг int.”Всеки тип int трябва да се съхранява в толкова байта, колкото предшественика му. За повечето системи един обект тип може да бъде преобразуван в съответния тип без проблем. Проблемът възниква при преобразуване от по-голям тип диапазон в по-малък тип диапазон или при преобразуване на подписано число в съответно неподписано число.

Всеки компилатор има максимална стойност, която може да вземе за краткото int. Ако число, по-високо от този максимум, предназначено за int, е присвоено на краткия int, компилаторът ще следва някакъв алгоритъм и ще върне число в диапазона на краткото int. Ако програмистът има късмет, компилаторът ще предупреди за проблеми с използването на неподходящо преобразуване. Същото обяснение се отнася за преобразувания от други типове int.

Потребителят трябва да се запознае с документацията на компилатора, за да определи ограничителните стойности за всеки тип обект.

Ако отрицателно подписано кратко int число трябва да бъде преобразувано в неподписано кратко int число, компилаторът ще следва някакъв алгоритъм и ще върне положително число в диапазона на неподписаното кратко int. Този вид преобразуване трябва да се избягва. Същото обяснение се отнася за преобразувания от други типове int.

Всяко цяло число, с изключение на 0, може да бъде преобразувано в логическо true. 0 се преобразува в Boolean false. Следният код илюстрира това:

int a = -27647;
плувка b = 2.5;
int c = 0;
bool a1 = a;
bool b1 = b;
bool c1 = c;
Cout<Cout<Cout<Резултатът е:

1 за вярно
1 за вярно
0 за false

Преобразувания с плаваща запетая

Типовете с плаваща запетая включват „float“, „double“ и „long double.”Типовете с плаваща запетая не се групират в подписани и неподписани, като цели числа. Всеки тип може да има подписан или неподписан номер. Тип с плаваща запетая трябва да има поне същата прецизност като своя предшественик. Тоест, „long double“ трябва да има еднаква или по-голяма точност на „double“, а „double“ трябва да има еднаква или по-голяма точност да „float“.”

Не забравяйте, че обхватът на тип с плаваща запетая не е непрекъснат; по-скоро е с малки стъпки. Колкото по-голяма е точността на типа, толкова по-малки са стъпките и толкова по-голям е броят на байтовете за съхраняване на номера. Така че, когато число с плаваща запетая се преобразува от тип с по-ниска точност в тип с по-висока точност, програмистът трябва да приеме фалшиво увеличаване на точността и евентуално увеличение на броя байтове за съхранение на числа. Когато число с плаваща запетая се преобразува от тип с по-висока точност в по-ниска, програмистът трябва да приеме загуба в точността. Ако броят на байтовете за съхранение на числа трябва да бъде намален, тогава компилаторът ще следва някакъв алгоритъм и ще върне число като заместител (което вероятно не е това, което програмистът иска). Освен това имайте предвид проблемите извън обхвата.

Плаващи-интегрални конверсии

Число с плаваща запетая се преобразува в цяло число чрез отрязване на дробната част. Следният код илюстрира това:

плувка f = 56.953;
int i = f;
Cout<Изходът е 56. Диапазоните за float и integer трябва да са съвместими.

Когато цяло число се преобразува в плувка, стойността, показана като плувка, е същата, каквато е била въведена като цяло число. Обаче еквивалентът на плувка може да е точната стойност или да има малка дробна разлика, която не се показва. Причината за дробната разлика е, че числата с плаваща запетая са представени в компютъра на малки дробни стъпки и затова представянето на цялото число би било съвпадение. Така че, въпреки че цялото число, показано като плувка, е същото, както е било въведено, дисплеят може да е приближение на това, което се съхранява.

Цялостно класиране на преобразуването

Всеки цяло число има ранг, който му е даден. Това класиране помага за конверсия. Класирането е относително; чиновете не са на фиксирани нива. С изключение на char и подписан char, няма две подписани цели числа с еднакъв ранг (ако приемем, че char е подписан). Неподписаните целочислени типове имат същото класиране като съответните им подписани цели числа. Класирането е както следва:

  • Ако приемем, че char е подписан, тогава char и подписан char имат същия ранг.
  • Рангът на подписан цял тип е по-голям от ранга на подписан цял тип на по-малък брой байтове за съхранение. И така, рангът на подписан дълъг дълъг int е по-голям от ранга на подписан дълъг int, който е по-голям от ранга на подписан int int, който е по-голям от ранга на подписан къс int, който е по-голям от ранга на подписан char.
  • Рангът на всеки неподписан цяло число е равен на ранга на съответния подписван цял тип.
  • Рангът на неподписан знак се равнява на ранг на подписан знак.
  • bool има най-малък ранг; рангът му е по-малък от този на подписания знак.
  • char16_t има същия ранг като късата int. char32_t има същия ранг като int. За компилатора на g ++ wchar_t има същия ранг като int.

Интегрални промоции

Integral Promotions е Integer Promotions. Няма причина цяло число от по-малко байтове да не може да бъде представено от цяло число от по-големи байтове. Integer Promotions се занимава с всичко, което следва:

  • Подписан кратък int (два байта) може да бъде преобразуван в подписан int (четири байта). Неподписан кратък int (два байта) може да бъде преобразуван в неподписан int (четири байта). Забележка: преобразуването на кратко int в дълго int или long long int води до загуба на байтове за съхранение (местоположение на обекта) и загуба на памет. Bool, char16_t, char32_t и wchar_t са освободени от тази промоция (с компилатора на g ++ char32_t и wchar_t имат еднакъв брой байтове).
  • С компилатора g ++ тип char16_t може да бъде преобразуван в подписан тип int или неподписан тип int; тип char32_t може да бъде преобразуван в подписан тип int или неподписан тип int; и тип wchar_t може да бъде преобразуван в подписан или неподписан тип int.
  • Тип bool може да бъде преобразуван в тип int. В този случай true става 1 (четири байта), а false става 0 (четири байта). Int може да бъде подписан или подписан.
  • Целочислена промоция съществува и за неразпределен тип изброяване - вижте по-късно.

Обичайни аритметични преобразувания

Обмислете следния код:

плувка f = 2.5;
int i = f;
Cout<Кодът се компилира, без да посочва предупреждение или грешка, давайки резултата от 2, което вероятно не е очакваното. = е двоичен оператор, защото отнема левия и десния операнд. Обмислете следния код:

int i1 = 7;
int i2 = 2;
float flt = i1 / i2;
Cout<Изходът е 3, но това е погрешно; трябваше да бъде 3.5. Операторът на деление, /, също е двоичен оператор.

C ++ има обичайни аритметични преобразувания, които програмистът трябва да знае, за да избегне грешки в кодирането. Обичайните аритметични преобразувания на двоични оператори са както следва:

  • Ако някой от операндите е от типа „long double“, тогава другият ще бъде преобразуван в long double.
  • В противен случай, ако някой от операндите е двоен, другият ще бъде преобразуван в двоен.
  • В противен случай, ако някой от операндите е float, другият ще бъде преобразуван в float. В горния код резултатът от i1 / i2 е официално 2; затова flt е 2. Резултатът от двоичния файл, /, се прилага като десен операнд към двоичния оператор, =. И така, крайната стойност на 2 е float (не int).

ИНАЧЕ, ИНТЕГРАЛНАТА ПРОМОЦИЯ ЩЕ СЕ СЛЕДВА ПО СЛЕДНОТО:

  • Ако и двата операнда са от един и същи тип, тогава не се извършва по-нататъшно преобразуване.
  • В противен случай, ако и двата операнда са подписани цели числа или и двата са неподписани цели числа, тогава операндът от типа с по-нисък целочислен ранг ще бъде преобразуван във типа на операнда с по-висок ранг.
  • В противен случай, ако единият операнд е подписан, а другият е неподписан, и ако типът на неподписания операнд е по-голям или равен на ранга на подписания тип операнд и ако стойността на подписания операнд е по-голяма или равна на нула, тогава подписаният операнд ще бъде преобразуван в неподписания операнд (с отчитане на обхвата). Ако подписаният операнд е отрицателен, тогава компилаторът ще следва алгоритъм и ще върне число, което може да не е приемливо за програмиста.
  • В противен случай, ако единият операнд е подписан цяло число, а другият е неподписан цяло число, и ако всички възможни стойности на типа на операнда с неподписан цял тип могат да бъдат представени от подписания цял тип, тогава неподписаният цял ​​тип ще да се преобразува в типа на операнда от подписания цял тип.
  • В противен случай двата операнда (char и bool например) ще бъдат преобразувани в неподписан цял тип.

Промоция с плаваща запетая

Типовете с плаваща запетая включват „float“, „double“ и „long double.”Типът с плаваща запетая трябва да има поне същата точност като предшественика си. Промоцията с плаваща запетая позволява преобразуване от float в double или от double в long double.

Преобразувания на показалеца

Показалец от един тип обект не може да бъде присвоен на указател от различен тип обект. Следният код няма да се компилира:

int id = 6;
int * intPtr = &id;
float idf = 2.5;
float * floatPtr = &idf;
intPtr = floatPtr; // грешка тук

Нулевият указател е указател, чиято адресна стойност е нула. Нулев указател от един тип обект не може да бъде присвоен на нулев указател от различен тип обект. Следният код няма да се компилира:

int id = 6;
int * intPtr = &id;
intPtr = 0;
float idf = 2.5;
float * floatPtr = &idf;
floatPtr = 0;
intPtr = floatPtr; // грешка тук

Константа на нулев указател от един тип обект не може да бъде присвоена на константа на нулев указател от различен тип обект. Следният код няма да се компилира:

int id = 6;
int * intPtr = &id;
int * const intPC = 0;
float idf = 2.5;
float * floatPtr = &idf;
float * const floatPC = 0;
intPC = floatPC; // грешка тук

На нулев указател може да бъде дадена различна адресна стойност за неговия тип. Следният код илюстрира това:

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

Изходът е 2.5.

Както се очаква, на константа за нулев указател не може да се присвоява никаква адресна стойност от своя тип. Следният код няма да се компилира:

float idf = 2.5;
float * const floatPC = 0;
floatPC = &idf; // грешка тук

Константата на нулев указател обаче може да бъде присвоена на обикновен указател, но от същия тип (това е очаквано). Следният код илюстрира това:

float idf = 2.5;
float * const floatPC = 0;
float * floatPter = &idf;
floatPter = floatPC; //ДОБРЕ
Cout << floatPter << '\n';

Изходът е 0.

Две нулеви стойности на показалеца от същия тип сравняват (==) равни.

Показалец към тип обект може да бъде присвоен на указател за void. Следният код илюстрира това:

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

Кодът се компилира без предупреждение или съобщение за грешка.

Функция за преобразуване на показалеца

Пойнтер към функция, която не би създала изключение, може да бъде присвоен на указател за функция. Следният код илюстрира това:

#include
използване на пространство от имена std;
void fn1 () noexcept

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

void fn2 ()

//изявления

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

func1 = &fn1;
func2 = &fn2;
func2 = &fn1;
func2 ();
връщане 0;

Изходът е с noexcept.

Булеви преобразувания

В C ++ обектите, които могат да доведат до false, включват „нула“, „нулев указател“ и „нулев член указател.”Всички други обекти водят до истина. Следният код илюстрира това:

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

Резултатът е:

0 // за false
0 // за false
1 // за вярно
1 // за вярно

Lvalue, prvalue и xvalue

Обмислете следния код:

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

Изходът е 35. В кода id и id1 са lvalues, защото идентифицират местоположение (обект) в паметта. Изходът 35 е първа стойност. Всеки литерал, с изключение на низов литерал, е първото значение. Другите стойности не са толкова очевидни, както в примерите по-долу. Обмислете следния код:

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

Ptr е стойност, тъй като идентифицира местоположение (обект) в паметта. От друга страна, pter не е стойност. Pter е указател, но не идентифицира никакво местоположение в паметта (не сочи към никакъв обект). Така че, pter е първото значение.

Обмислете следния код:

void fn ()

//изявления

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

Fn () и (* func) () са изрази lvalue, тъй като идентифицират обект (функция) в паметта. От друга страна, (* functn) () не е израз на стойност. (* functn) () е указател към функция, но не идентифицира нито един обект в паметта (не сочи към която и да е функция в паметта). И така, (* functn) () е израз на първа стойност.

Сега помислете за следния код:

struct S

int n;
;
S obj;

S е клас, а obj е обект, създаден от класа. Obj идентифицира обект в паметта. Класът е обобщена единица. Така че, S наистина не идентифицира нито един обект в паметта. Казва се, че S е обект без име. S също е израз на първа стойност.

Фокусът на тази статия е върху стойностите. Prvalue означава чиста rvalue.

Xvalue

Xvalue означава Expiring Value. Временните стойности са изтичащи стойности. Lvalue може да се превърне в xvalue. Първата стойност също може да се превърне в xvalue. Фокусът на тази статия е върху стойностите. Xvalue е lvalue или неназована референтна стойност на rvalue, чието съхранение може да бъде използвано повторно (обикновено защото е към края на живота си). Помислете за следния код, който работи:

struct S

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

Изразът „int q = S ().н;" копира каквато и стойност n има в q. S () е просто средство; не е редовно използван израз. S () е първа стойност, чиято употреба я е превърнала в xvalue.

Преобразувания Lvalue към rvalue

Обмислете следното твърдение:

int ii = 70;

70 е първа стойност (rvalue) и ii е стойност. Сега помислете за следния код:

int ii = 70;
int tt = ii;

Във второто твърдение ii е в положението на първа стойност, така че ii става първа стойност там. С други думи, компилаторът преобразува ii в първо значение имплицитно. Тоест, когато lvalue се използва в ситуация, в която изпълнението очаква първа стойност, реализацията преобразува lvalue в първа стойност.

Преобразувания от масив към указател

Помислете за следния код, който работи:

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

Изходът е б. Първият израз е израз и е указател към символ. Но към кой знак е посочено изявлението? - Няма характер. Така че, това е първа ценност, а не стойност. Вторият израз е масив, в който q [] е израз lvalue. Третото изражение превръща prvalue, p в израз lvalue, който сочи към първия елемент на масива.

Преобразувания от функция към указател

Обмислете следната програма:

#include
използване на пространство от имена std;
void (* func) ();
void fn ()

//изявления

int main ()

func = &fn;
връщане 0;

Изразът „void (* func) ();“ е указател към функция. Но към коя функция сочи изразът? - Няма функция. Така че, това е първа ценност, а не стойност. Fn () е дефиниция на функция, където fn е израз на стойност. В main (), „func = &fn;”Превръща prvalue, func, в израз lvalue, който сочи към функцията, fn ().

Временни конверсии на материализация

В C ++ първото значение може да бъде преобразувано в x стойност от същия тип. Следният код илюстрира това:

struct S

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

Тук първото значение, S (), е преобразувано в xvalue. Като xvalue няма да продължи дълго - вижте повече обяснения по-горе.

Квалификационни конверсии

Тип, отговарящ на условията за cv, е тип, квалифициран по запазената дума „const“ и / или запазената дума „volatile“.”

Класирането на Cv също се класира. Никаква cv-квалификация не е по-малка от квалификация „const“, което е по-малко от квалификация „const volatile“. Никоя cv-квалификация не е по-малка от „volatile“ квалификация, което е по-малко от „const volatile“ квалификация. И така, има два потока от квалификационно класиране. Един тип може да бъде по-квалифициран за cv от друг.

Типът с по-ниска първа стойност cv може да се преобразува в по-квалифициран cv тип първа. И двата типа трябва да са указател към cv.

Заключение

C ++ обектите могат да бъдат преобразувани от един тип в свързан тип имплицитно или изрично. Програмистът обаче трябва да разбере какво може да се преобразува и какво не, и под каква форма. Преобразуването може да се извърши в следните домейни: Интегрални конверсии, Преобразувания с плаваща запетая, Преобразувания с плаваща точка, Обичайни аритметични преобразувания, Преобразувания на указатели, Преобразувания от функция към указател, Булеви преобразувания, Преобразувания от Lvalue към Rvalue, Преобразувания от масив към указател , Преобразувания от функция към указател, Временни преобразувания на материализация и Преобразувания за квалификация.

Най-добрите игри за игра с ръчно проследяване
Oculus Quest наскоро представи страхотната идея за ръчно проследяване без контролери. С непрекъснато нарастващия брой игри и дейности, които изпълнява...
Как да покажете OSD наслагване в приложения на цял екран за Linux и игри
Играта на цял екран или използване на приложения в режим на цял екран без разсейване може да ви откъсне от съответната системна информация, видима в п...
Топ 5 карти за залавяне на игри
Всички сме виждали и обичаме поточни игри в YouTube. PewDiePie, Jakesepticye и Markiplier са само някои от най-добрите геймъри, които са спечелили мил...