Conversions standard C ++

Conversions standard C ++
Il existe deux types d'entités en C ++, les types fondamentaux et les types de composés. Les types fondamentaux sont les types scalaires. Les types de composés sont le reste des types d'entités. La conversion peut avoir lieu d'un type d'entité à un autre type approprié. Considérez le programme suivant: #include
#inclure
Utilisation de Namespace Std;
int main()

int rt1 = sqrt (5);
int rt2 = sqrt (8);
couter<retour 0;

La sortie est 2, 2, ce qui signifie que le programme a renvoyé la racine carrée de 5 comme 2 et la racine carrée de 8 également comme 2. Ainsi, les deux premières déclarations du principal() La fonction a terrassé les réponses de la racine carrée de 5 et de la racine carrée de 8. Cet article ne discute pas de revêtements de sol ou de plafond en C++. Cet article traite de la conversion d'un type C ++ en un autre type C ++ approprié; indiquant toute approximation de valeur effectuée, la perte de précision ou la contrainte ajoutée ou supprimée. La connaissance de base de C ++ est une condition préalable pour comprendre cet article.

Contenu de l'article

  • Conversions intégrales
  • Conversions à virgule flottante
  • Conversions à intégration flottante
  • Classement de conversion entier
  • Promotions intégrales
  • Conversions arithmétiques habituelles
  • Promotion de point flottante
  • Conversions du pointeur
  • Fonctions pour pointer les conversions
  • Conversions booléennes
  • LVALUE, PRVALUE et XVALUE
  • Xvalue
  • Conversions Lvalue-to-Rvalue
  • Conversions de table-pointer
  • Conversions de fonction à pointeur
  • Conversions de matérialisation temporaire
  • Conversions de qualification
  • Conclusion

Conversions intégrales

Les conversions intégrales sont des conversions entières. Les entiers non signés incluent «Char non signé», «UNSIGNED Short Int», «Unsigned int», «unsigned long int» et «non signé long int.«Les entiers signés correspondants comprennent« Signed Char »,« Short int »,« int »,« long int »et« long int int."Chaque type int doit être maintenu dans autant d'octets que son prédécesseur. Pour la plupart des systèmes, un type d'entité peut être converti en un type correspondant sans aucun problème. Le problème se produit lors de la conversion d'un type de plage plus grand en un type de plage plus petit, ou lors de la conversion d'un numéro signé en un nombre non signé correspondant.

Chaque compilateur a une valeur maximale qu'elle peut prendre pour le court int. Si un nombre supérieur à ce maximum, destiné à un INT, est attribué à l'intrément court, le compilateur suivra un algorithme et renverra un nombre dans la plage du court int. Si le programmeur a de la chance, le compilateur avertira des problèmes à utiliser une conversion inappropriée. La même explication s'applique aux conversions d'autres types int.

L'utilisateur doit consulter la documentation du compilateur pour déterminer les valeurs limitantes pour chaque type d'entité.

Si un numéro d'intrection court signé négatif doit être converti en un numéro d'int court non signé, le compilateur suivra un algorithme et renverra un nombre positif dans la plage de l'intrément court non signé. Ce type de conversion doit être évité. La même explication s'applique aux conversions d'autres types int.

Tout numéro entier, sauf 0, peut être converti en booléen true. 0 est converti en booléen faux. Le code suivant illustre ceci:

int a = -27647;
Float b = 2.5;
int c = 0;
bool a1 = a;
bool b1 = b;
bool c1 = c;
couter<couter<couter<La sortie est:

1
1
0

1 signifie vrai, et 0 signifie faux dans la sortie

Conversions à virgule flottante

Les types de points flottants incluent «Float», «Double» et «Long Double.«Les types de points flottants ne sont pas regroupés en signé et non signé, comme les entiers. Chaque type peut avoir un numéro signé ou non signé. Un type à virgule flottante devrait avoir au moins la même précision que son prédécesseur. C'est-à-dire que «long double» devrait avoir une précision égale ou supérieure à «double» et «double» devrait avoir une précision égale ou supérieure à «flotter."

N'oubliez pas que la plage d'un type à virgule flottante n'est pas continue; c'est plutôt en petites étapes. Plus la précision du type est grande, plus les étapes sont petites, et plus le nombre d'octets est faible pour stocker le nombre. Ainsi, lorsqu'un nombre de points flottants est converti d'un type de précision inférieur en un type de précision plus élevé, le programmeur doit accepter une fausse augmentation de la précision et une augmentation possible du nombre d'octets pour le storage numérique. Lorsqu'un nombre de points flottants est converti d'un type de précision plus élevé en un type de précision inférieur, le programmeur doit accepter une perte de précision. Si le nombre d'octets pour le stockage numérique doit être réduit, le compilateur suivra un algorithme et renverra un nombre en tant que substitut (ce qui n'est probablement pas ce que le programmeur veut). Gardez également à l'esprit les problèmes hors gamme.

Conversions à intégration flottante

Un numéro de point flottant est converti en un entier en tronquant la partie fractionnée. Le code suivant illustre ceci:

Float f = 56.953;
int i = f;
couter<La sortie est 56. Les gammes du flotteur et de l'entier doivent être compatibles.

Lorsqu'un entier est converti en flotteur, la valeur affichée comme un flotteur est la même que celle tapée comme un entier. Cependant, l'équivalent flotteur peut être la valeur exacte ou avoir une légère différence fractionnée qui n'est pas affichée. La raison de la différence fractionnaire est que les nombres à virgule flottante sont représentés dans l'ordinateur en petites étapes fractionnaires, et donc représenter exactement le rendement serait une coïncidence. Ainsi, bien que l'entier affiché comme un flotteur soit le même que celle tapée, l'affichage peut être une approximation de ce qui est stocké.

Classement de conversion entier

Tout type entier a un rang qui lui a été donné. Ce classement aide à la conversion. Le classement est relatif; Les rangs ne sont pas à des niveaux fixes. À l'exception de Char et de Char signé, il n'y a pas deux entiers signés n'ont le même rang (en supposant que Char est signé). Les types entiers non signés ont le même classement que leurs types entiers signés correspondants. Le classement est le suivant:

  • En supposant que Char est signé, alors Char et Signed Char ont le même rang.
  • Le rang d'un type entier signé est supérieur au rang d'un type entier signé d'un plus petit nombre d'octets de stockage. Ainsi, le rang de signé Long Long INT est supérieur au rang de signé long Int, qui est supérieur au rang d'intre.
  • Le rang de tout type entier non signé est égal au rang du type entier signé correspondant.
  • Le rang de char non signé est égal au rang de char signé.
  • Bool a le moins de rang; son rang est inférieur à celui de Char signé.
  • char16_t a le même rang que le court int. char32_t a le même rang que l'int. Pour le compilateur G ++, WCHAR_T a le même rang que l'int.

Promotions intégrales

Les promotions intégrales sont des promotions entières. Il n'y a aucune raison pour qu'un entier de moins d'octets ne puisse pas être représenté par un entier de plus grands octets. Les promotions entières traitent de tout ce qui suit:

  • Un INT court signé (deux octets) peut être converti en un INT signé (quatre octets). Un INT court non signé (deux octets) peut être converti en un INT non signé (quatre octets). Remarque: la conversion d'un INT court en un long int ou une longue longue longue mène à un gaspillage de stockage (emplacement d'objet) des octets et à un gaspillage de mémoire. BOOL, CHAR16_T, CHAR32_T et WCHAR_T sont exemptés de cette promotion (avec le compilateur G ++, CHAR32_T et WCHAR_T ont le même nombre d'octets).
  • Avec le compilateur G ++, un type CHAR16_T peut être converti en type INT signé ou un type int non signé; Un type CHAR32_T peut être converti en type INT signé ou un type int non signé; et un type wchar_t peut être converti en un type int signé ou non signé.
  • Un type bool peut être converti en un type int. Dans ce cas, le vrai devient 1 (quatre octets) et FAUX devient 0 (quatre octets). INT peut être signé ou signé.
  • La promotion entière existe également pour le type de dénombrement noncopé - voir plus tard.

Conversions arithmétiques habituelles

Considérez le code suivant:

flotter f = 2.5;
int i = f;
couter<Le code compile sans indiquer aucun avertissement ou erreur, donnant la sortie de 2, ce qui n'est probablement pas ce qui était attendu. = est un opérateur binaire car il prend un opérande gauche et droit. Considérez le code suivant:

int i1 = 7;
int i2 = 2;
float flt = i1 / i2;
couter<La sortie est 3, Mais c'est faux; il était censé être 3.5. L'opérateur de division, /, est également un opérateur binaire.

C ++ a des conversions arithmétiques habituelles que le programmeur doit connaître pour éviter les erreurs de codage. Les conversions arithmétiques habituelles sur les opérateurs binaires sont les suivantes:

  • Si l'un ou l'autre opérande est du type «long double», alors l'autre sera converti en double double.
  • Sinon, si l'un ou l'autre opérande est double, l'autre sera converti en double.
  • Sinon, si l'un ou l'autre opérande est flottant, l'autre sera converti pour flotter. Dans le code ci-dessus, le résultat de I1 / I2 est officiellement 2; C'est pourquoi Flt est 2. Le résultat du binaire, /, est appliqué comme le bon opérande à l'opérateur binaire, =. Ainsi, la valeur finale de 2 est un flotteur (pas un int).

Sinon, la promotion entière aurait lieu comme suit:

  • Si les deux opérandes sont du même type, alors aucune autre conversion n'a lieu.
  • Sinon, si les deux opérandes sont signés de types entiers ou les deux sont des types entiers non signés, l'opérande du type avec le rang entier inférieur sera converti au type d'opérande avec le rang supérieur.
  • Sinon, si un opérande est signé et l'autre n'est pas signé, et si le type d'opérande non signé est supérieur ou égal au rang du type d'opérande signé, et si la valeur de l'opérande signé est supérieure ou égale à zéro, alors L'opérande signé sera converti en type d'opérande non signé (avec une plage prise en considération). Si l'opérande signé est négatif, le compilateur suivra un algorithme et renverra un nombre qui peut ne pas être acceptable pour le programmeur.
  • Sinon, si un opérande est un type entier signé et que l'autre est un type entier non signé, et si toutes les valeurs possibles du type de l'opérande avec le type entier non signé peuvent être représentées par le type entier signé, alors le type entier non signé sera être converti au type de l'opérande du type entier signé.
  • Sinon, les deux opérandes (un char et un bool, par exemple) seraient convertis en type entier non signé.

Promotion de point flottante

Les types de points flottants incluent «Float», «Double» et «Long Double."Un type de point flottant devrait avoir au moins la même précision que son prédécesseur. La promotion à virgule flottante permet une conversion de Float à double ou de double à long.

Conversions du pointeur

Un pointeur d'un type d'objet ne peut pas être attribué à un pointeur d'un type d'objet différent. Le code suivant ne compilera pas:

int id = 6;
int * intptr = &id;
idf float = 2.5;
float * floatptr = &idf;
intptr = floatptr; // erreur ici

Un pointeur nul est un pointeur dont la valeur d'adresse est nul. Un pointeur nul d'un type d'objet ne peut pas être attribué à un pointeur nul d'un type d'objet différent. Le code suivant ne compilera pas:

int id = 6;
int * intptr = &id;
intptr = 0;
idf float = 2.5;
float * floatptr = &idf;
floatptr = 0;
intptr = floatptr; // erreur ici

Un pointeur null const d'un type d'objet ne peut pas être attribué à un pointeur null const d'un type d'objet différent. Le code suivant ne compilera pas:

int id = 6;
int * intptr = &id;
int * const intpc = 0;
idf float = 2.5;
float * floatptr = &idf;
float * const floatpc = 0;
intpc = floatpc; // erreur ici

Un pointeur nul peut recevoir une valeur d'adresse différente pour son type. Le code suivant illustre ceci:

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

La sortie est 2.5.

Comme prévu, une constante de pointeur nulle ne peut être attribuée à aucune valeur d'adresse de son type. Le code suivant ne compilera pas:

idf float = 2.5;
float * const floatpc = 0;
floatpc = &idf; // erreur ici

Cependant, une constante de pointeur nulle peut être attribuée à un pointeur ordinaire, mais du même type (ceci est à prévoir). Le code suivant illustre ceci:

idf float = 2.5;
float * const floatpc = 0;
float * flottepter = &idf;
FloatPter = floatpc; //D'ACCORD
couter << floatPter << '\n';

La sortie est 0.

Deux valeurs de pointeur nulle du même type compare (==) égal.

Un pointeur vers un type d'objet peut être attribué à un pointeur pour vide. Le code suivant illustre ceci:

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

Le code se compile sans un message d'avertissement ou d'erreur.

Fonctions pour pointer les conversions

Un pointeur vers une fonction qui ne lancera pas d'exception peut être attribuée à un pointeur pour fonctionner. Le code suivant illustre ceci:

#inclure
Utilisation de Namespace Std;
void fn1 () noexcept

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

void fn2 ()

// déclarations

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

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

La sortie est sans.

Conversions booléennes

En C ++, les entités qui peuvent entraîner un faux incluent «zéro», «pointeur nul» et «pointeur null.«Toutes les autres entités se traduisent par une vraie. Le code suivant illustre ceci:

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

La sortie est:

0 // pour false
0 // pour false
1 // pour vrai
1 // pour vrai

LVALUE, PRVALUE ET XVALUE

Considérez le code suivant:

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

La sortie est 35. Dans le code, ID et ID1 sont des LVAlues car ils identifient un emplacement (objet) en mémoire. La sortie 35 est un prvalue. Tout littéral, à l'exception d'un littéral de cordes, est un prvalue. D'autres prvalues ​​ne sont pas si évidents, comme dans les exemples qui suivent. Considérez le code suivant:

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

PTR est un LVALUE car il identifie un emplacement (objet) en mémoire. D'un autre côté, Pter n'est pas un lvalue. Pter est un pointeur, mais il n'identifie aucun emplacement en mémoire (il ne pointe de aucun objet). Donc, Pter est un prvalue.

Considérez le code suivant:

void fn ()

// déclarations

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

Fn () et (* func) () sont des expressions lvalues ​​car elles identifient une entité (fonction) en mémoire. D'un autre côté, (* functn) () n'est pas une expression lvalue. (* functn) () est un pointeur vers une fonction, mais il n'identifie aucune entité en mémoire (il ne pointe pas vers aucune fonction en mémoire). Ainsi, (* functn) () est une expression de PRValue.

Maintenant, considérez le code suivant:

structure

int n;
;
S obj;

S est une classe et OBJ est un objet instancié de la classe. OBJ identifie un objet en mémoire. Une classe est une unité généralisée. Donc, S n'identifie pas vraiment d'objet en mémoire. S est dit être un objet sans nom. S est également une expression de la valeur.

L'objectif de cet article est sur les prvalues. PRVALUE signifie pur.

Xvalue

Xvalue signifie expirant la valeur. Les valeurs temporaires expirent les valeurs. Une lvalue peut devenir un xvalue. Un prvalue peut également devenir un xvalue. L'objectif de cet article est sur les prvalues. Un xvalue est une lVALUE ou une référence de la valeur sans nom dont le stockage peut être réutilisé (généralement parce qu'il est près de la fin de sa durée de vie). Considérez le code suivant qui fonctionne:

structure

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

L'expression «int q = s ().n; » copies quelle que soit la valeur n que nous tient à q. S () n'est qu'un moyen; Ce n'est pas une expression régulièrement utilisée. S () est un prvalue dont l'utilisation l'a convertie en xvalue.

Conversions Lvalue-to-Rvalue

Considérez la déclaration suivante:

int ii = 70;

70 est un prvalue (rvalue) et II est un lvalue. Maintenant, considérez le code suivant:

int ii = 70;
int tt = ii;

Dans la deuxième déclaration, II est dans la situation d'un prvalue, donc II devient un prvalue là-bas. En d'autres termes, le compilateur convertit II en un prvalue implicitement. Autrement dit, lorsqu'une LVALUE est utilisée dans une situation dans laquelle la mise en œuvre s'attend à un prvalue, la mise en œuvre convertit la LVALUE en un PRValue.

Conversions de table-pointer

Considérez le code suivant qui fonctionne:

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

La sortie est b. La première instruction est une expression et est un pointeur vers un personnage. Mais à quel personnage est la déclaration pointant? - Pas de caractère. Donc, c'est un prvalue et non une lvalue. La deuxième instruction est un tableau dans lequel Q [] est une expression lvalue. La troisième déclaration transforme le prvalue, p, en une expression lvalue, qui pointe vers le premier élément du tableau.

Conversions de fonction à pointeur

Considérez le programme suivant:

#inclure
Utilisation de Namespace Std;
void (* func) ();
void fn ()

// déclarations

int main()

func = &fn;
retour 0;

L'expression «vide (* func) ();» est un pointeur vers une fonction. Mais à quelle fonction est l'expression pointant? - Pas de fonction. Donc, c'est un prvalue et non une lvalue. Fn () est une définition de fonction, où fn est une expression lvalue. Dans main (), «func = &fn;”Transforme le prvalue, func, en une expression lvalue qui pointe vers la fonction, fn ().

Conversions de matérialisation temporaire

En C ++, un prvalue peut être converti en un xvalue du même type. Le code suivant illustre ceci:

structure

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

Ici, le prvalue, s (), a été converti en xvalue. En tant que xvalue, cela ne durerait pas longtemps - voir plus d'explication ci-dessus.

Conversions de qualification

Un type qualifié CV est un type qualifié par le mot réservé, «const» et / ou le mot réservé, «Volatile."

La qualification CV est également classée. Aucune qualification CV n'est inférieure à la qualification «const», ce qui est inférieur à la qualification «const volatile». Aucune qualification de CV n'est inférieure à la qualification «volatile», ce qui est inférieur à la qualification «const volatile». Il y a donc deux flux de classement de qualification. Un type peut être plus qualifié par CV qu'un autre.

Un type qualifié CV inférieur peut être converti en un type PRValue qualifié plus CV. Les deux types doivent être pointeurs à CV.

Conclusion

Les entités C ++ peuvent être converties d'un type à un type connexe implicitement ou explicitement. Cependant, le programmeur doit comprendre ce qui peut être converti et ce qui ne peut pas être converti, et en quelle forme. La conversion peut avoir lieu dans les domaines suivants: conversions intégrales, conversions à virgule flottante, conversions flottantes-intégales, conversions arithmétiques habituelles, conversions de pointeur, fonctions en fonction des pointeurs, conversions booléennes, conversions lvalue-to-rvalue, conversions de tableau à point-points , Conversions de fonction-là, conversions de matérialisation temporaire et conversions de qualification.