Conversion de type - Type conversion
Dans l'informatique , la conversion de type , la coulée de type , la contrainte de type et de type jonglage sont différentes façons de changer une expression d'un type de données à un autre. Un exemple serait la conversion d'une valeur entière en une valeur à virgule flottante ou sa représentation textuelle sous forme de chaîne , et vice versa. Les conversions de types peuvent tirer parti de certaines fonctionnalités des hiérarchies de types ou des représentations de données . Deux aspects importants d'une conversion de type sont de savoir si elle se produit implicitement (automatiquement) ou explicitement , et si la représentation de données sous-jacente est convertie d'une représentation en une autre, ou si une représentation donnée est simplement réinterprétée comme la représentation d'un autre type de données. En général, les types de données primitifs et composés peuvent être convertis.
Chaque langage de programmation a ses propres règles sur la façon dont les types peuvent être convertis. Les langages avec un typage fort font généralement peu de conversion implicite et découragent la réinterprétation des représentations, tandis que les langages avec un typage faible effectuent de nombreuses conversions implicites entre les types de données. Un langage de typage faible permet souvent de forcer le compilateur à interpréter arbitrairement un élément de données comme ayant des représentations différentes - cela peut être une erreur de programmation non évidente ou une méthode technique pour traiter directement le matériel sous-jacent.
Dans la plupart des langues, le mot coercition est utilisé pour désigner une conversion implicite , soit pendant la compilation, soit pendant l' exécution . Par exemple, dans une expression mélangeant des nombres entiers et à virgule flottante (comme 5 + 0,1), le compilateur convertira automatiquement la représentation entière en représentation à virgule flottante afin que les fractions ne soient pas perdues. Les conversions de types explicites sont soit indiquées en écrivant du code supplémentaire (par exemple en ajoutant des identificateurs de type ou en appelant des routines intégrées ) soit en codant des routines de conversion que le compilateur utilisera lorsqu'il s'arrêterait autrement avec une incompatibilité de type.
Dans la plupart des langages de type ALGOL , tels que Pascal , Modula-2 , Ada et Delphi , la conversion et le transtypage sont des concepts distinctement différents. Dans ces langages, la conversion fait référence au changement implicite ou explicite d'une valeur d'un format de stockage de type de données à un autre, par exemple un entier 16 bits en un entier 32 bits. Les besoins de stockage peuvent changer à la suite de la conversion, y compris une éventuelle perte de précision ou troncature. Le mot cast , quant à lui, fait référence au changement explicite de l' interprétation du motif binaire représentant une valeur d'un type à un autre. Par exemple, 32 bits contigus peuvent être traités comme un tableau de 32 booléens, une chaîne de 4 octets, un entier 32 bits non signé ou une valeur à virgule flottante simple précision IEEE. Étant donné que les bits stockés ne sont jamais modifiés, le programmeur doit connaître les détails de bas niveau tels que le format de représentation, l'ordre des octets et les besoins d'alignement, pour effectuer une conversion significative.
Dans la famille des langages C et ALGOL 68 , le mot cast fait généralement référence à une conversion de type explicite (par opposition à une conversion implicite), provoquant une certaine ambiguïté quant à savoir s'il s'agit d'une réinterprétation d'un modèle binaire ou d'une représentation réelle de données. conversion. Plus important est la multitude de façons et de règles qui s'appliquent au type de données (ou classe) localisé par un pointeur et comment un pointeur peut être ajusté par le compilateur dans des cas comme l'héritage d'objet (classe).
Comparaison des langues
Langages de type C
Conversion de type implicite
La conversion de type implicite, également connue sous le nom de coercition , est une conversion de type automatique par le compilateur . Certains langages de programmation permettent aux compilateurs de fournir une coercition ; d'autres l'exigent.
Dans une expression de type mixte, les données d'un ou plusieurs sous - types peuvent être converties en un supertype selon les besoins lors de l' exécution afin que le programme s'exécute correctement. Par exemple, ce qui suit est un code de langage C légal :
double d;
long l;
int i;
if (d > i) d = i;
if (i > l) l = i;
if (d == l) d *= 2;
Bien que d , l et i appartiennent à des types de données différents, ils seront automatiquement convertis en types de données égaux à chaque fois qu'une comparaison ou une affectation est exécutée. Ce comportement doit être utilisé avec prudence, car des conséquences inattendues peuvent survenir. Des données peuvent être perdues lors de la conversion de représentations à virgule flottante en nombre entier, car les composants fractionnaires des valeurs à virgule flottante seront tronqués (arrondis vers zéro). Inversement, la précision peut être perdue lors de la conversion de représentations d'entier en virgule flottante, car un type à virgule flottante peut être incapable de représenter exactement un type entier. Par exemple, il float
peut s'agir d'un type simple précision IEEE 754 , qui ne peut pas représenter exactement l'entier 16777217, alors qu'un type entier 32 bits peut le faire. Cela peut conduire à un comportement non intuitif, comme le montre le code suivant :
#include <stdio.h>
int main(void)
{
int i_value = 16777217;
float f_value = 16777216.0;
printf("The integer is: %d\n", i_value);
printf("The float is: %f\n", f_value);
printf("Their equality: %d\n", i_value == f_value);
}
Sur les compilateurs qui implémentent les flottants en simple précision IEEE et les ints au moins sur 32 bits, ce code donnera cette impression particulière :
The integer is: 16777217 The float is: 16777216.000000 Their equality: 1
Notez que 1 représente l'égalité dans la dernière ligne ci-dessus. Ce comportement étrange est dû à une conversion implicite de i_value
en float lorsqu'il est comparé à f_value
. La conversion entraîne une perte de précision, ce qui rend les valeurs égales avant la comparaison.
Points importants à retenir :
-
float
à desint
causes troncature , à savoir le retrait de la partie décimale. -
double
àfloat
cause de l' arrondissement des chiffres. -
long
àint
cause de l' excès de l' abandon des bits d'ordre supérieur.
Type de promotion
Un cas particulier de conversion de type implicite est la promotion de type, où le compilateur développe automatiquement la représentation binaire des objets de type entier ou à virgule flottante. Les promotions sont couramment utilisées avec des types plus petits que le type natif de l' unité arithmétique et logique (ALU) de la plate-forme cible , avant les opérations arithmétiques et logiques, pour rendre de telles opérations possibles, ou plus efficaces si l'ALU peut fonctionner avec plusieurs types. C et C++ effectuent une telle promotion pour les objets de types booléen, caractère, caractère large, énumération et entier court qui sont promus en int, et pour les objets de type float, qui sont promus en double. Contrairement à d'autres conversions de type, les promotions ne perdent jamais en précision et ne modifient jamais la valeur stockée dans l'objet.
En Java :
int x = 3;
double y = 3.5;
System.out.println(x + y); // The output will be 6.5
Conversion de type explicite
La conversion de type explicite est une conversion de type qui est explicitement définie dans un programme (au lieu d'être effectuée par un compilateur pour la conversion de type implicite). Il est défini par l'utilisateur dans le programme.
double da = 3.3;
double db = 3.3;
double dc = 3.4;
int result = (int)da + (int)db + (int)dc; // result == 9
// if implicit conversion would be used (as with "result = da + db + dc"), result would be equal to 10
Il existe plusieurs types de conversion explicite.
- vérifié
- Avant que la conversion ne soit effectuée, une vérification d'exécution est effectuée pour voir si le type de destination peut contenir la valeur source. Sinon, une condition d'erreur est levée.
- décoché
- Aucune vérification n'est effectuée. Si le type de destination ne peut pas contenir la valeur source, le résultat n'est pas défini.
- motif de bits
- La représentation binaire brute de la source est copiée mot à mot, et elle est réinterprétée en fonction du type de destination. Ceci peut également être réalisé via l' aliasing .
Dans les langages de programmation orientés objet , les objets peuvent également être transtypés : une référence d'une classe de base est transtypée vers l'une de ses classes dérivées.
C# et C++
En C# , la conversion de type peut être effectuée d'une manière sûre ou non (c'est-à-dire similaire à C), la première étant appelée cast de type vérifié .
Animal animal = new Cat();
Bulldog b = (Bulldog) animal; // if (animal is Bulldog), stat.type(animal) is Bulldog, else an exception
b = animal as Bulldog; // if (animal is Bulldog), b = (Bulldog) animal, else b = null
animal = null;
b = animal as Bulldog; // b == null
En C++, un effet similaire peut être obtenu en utilisant la syntaxe de transtypage de style C++ .
Animal* animal = new Cat;
Bulldog* b = static_cast<Bulldog*>(animal); // compiles only if either Animal or Bulldog is derived from the other (or same)
b = dynamic_cast<Bulldog*>(animal); // if (animal is Bulldog), b = (Bulldog*) animal, else b = nullptr
Bulldog& br = static_cast<Bulldog&>(*animal); // same as above, but an exception will be thrown if a nullptr was to be returned
// this is not seen in code where exception handling is avoided
animal = nullptr;
b = dynamic_cast<Bulldog*>(animal); // b == nullptr
delete animal; // always free resources
Eiffel
Dans Eiffel, la notion de conversion de types est intégrée dans les règles du système de types. La règle d'affectation indique qu'une affectation, telle que :
x := y
est valide si et seulement si le type de son expression source, y
dans ce cas, est compatible avec le type de son entité cible, x
dans ce cas. Dans cette règle, compatible avec signifie que le type de l'expression source est conforme ou convertit à celui de la cible. La conformité des types est définie par les règles familières du polymorphisme en programmation orientée objet . Par exemple, dans l'affectation ci-dessus, le type de y
est conforme au type de x
si la classe sur laquelle y
est basée est un descendant de celle sur laquelle x
est basée.
Définition de la conversion de type dans Eiffel
Les actions de conversion de type dans Eiffel, en particulier les conversions vers et les conversions à partir de, sont définies comme :
Un type basé sur une classe CU se convertit en un type T basé sur une classe CT (et T convertit de U) si soit
- CT a une procédure de conversion utilisant U comme type de conversion, ou
- CU a une requête de conversion répertoriant T comme type de conversion
Exemple
Eiffel est un langage entièrement compatible avec Microsoft .NET Framework . Avant le développement de .NET, Eiffel disposait déjà de bibliothèques de classes étendues. L'utilisation des bibliothèques de types .NET, en particulier avec les types couramment utilisés tels que les chaînes, pose un problème de conversion. Les logiciels Eiffel existants utilisent les classes de chaînes (telles que STRING_8
) des bibliothèques Eiffel, mais les logiciels Eiffel écrits pour .NET doivent utiliser la classe de chaînes .NET ( System.String
) dans de nombreux cas, par exemple lors de l'appel de méthodes .NET qui attendent des éléments du .NET type à passer en argument. Ainsi, la conversion de ces types dans les deux sens doit être aussi transparente que possible.
my_string: STRING_8 -- Native Eiffel string
my_system_string: SYSTEM_STRING -- Native .NET string
...
my_string := my_system_string
Dans le code ci-dessus, deux chaînes sont déclarées, une de chaque type différent ( SYSTEM_STRING
est l'alias compatible Eiffel pour System.String). Parce que System.String
n'est pas conforme à STRING_8
, l'affectation ci-dessus n'est valide que si elle est System.String
convertie en STRING_8
.
La classe Eiffel STRING_8
a une procédure de conversion make_from_cil
pour les objets de type System.String
. Les procédures de conversion sont également toujours désignées comme des procédures de création (similaires aux constructeurs). Voici un extrait de la STRING_8
classe :
class STRING_8
...
create
make_from_cil
...
convert
make_from_cil ({SYSTEM_STRING})
...
La présence de la procédure de conversion rend l'affectation :
my_string := my_system_string
équivalent sémantiquement à :
create my_string.make_from_cil (my_system_string)
dans lequel my_string
est construit comme un nouvel objet de type STRING_8
avec un contenu équivalent à celui de my_system_string
.
Pour gérer une affectation avec la source et la cible d'origine inversées :
my_system_string := my_string
la classe STRING_8
contient également une requête de conversion to_cil
qui produira un à System.String
partir d'une instance de STRING_8
.
class STRING_8
...
create
make_from_cil
...
convert
make_from_cil ({SYSTEM_STRING})
to_cil: {SYSTEM_STRING}
...
La tâche:
my_system_string := my_string
alors, devient équivalent à :
my_system_string := my_string.to_cil
Dans Eiffel, la configuration de la conversion de type est incluse dans le code de classe, mais semble alors se produire aussi automatiquement que la conversion de type explicite dans le code client. Le inclut non seulement les affectations, mais également d'autres types de pièces jointes, telles que la substitution d'arguments (paramètres).
Rouiller
Rust ne fournit aucune conversion de type implicite (coercition) entre les types primitifs. Mais, une conversion de type explicite (casting) peut être effectuée à l'aide du as
mot - clé.
println!("1000 as a u16 is: {}", 1000 as u16);
Problèmes de sécurité
Dans le piratage , le transtypage est l'utilisation abusive de la conversion de type pour modifier temporairement le type de données d' une variable par rapport à la façon dont il a été défini à l'origine. Cela offre des opportunités aux pirates, car dans la conversion de type après qu'une variable est "transformée" pour devenir un type de données différent, le compilateur traitera cette variable piratée comme le nouveau type de données pour cette opération spécifique.
Voir également
- Downcasting
- Informations sur le type d'exécution#Diffusion dynamique et diffusion Java
- Type de jeu de mots
Les références
Liens externes
- Casting à Ada
- Caster en C++
- Guide de référence C++ Pourquoi je déteste les opérateurs de distribution C++, par Danny Kalev
- Caster en Java
- Conversions implicites en C#
- Casting de type implicite sur Cppreference.com
- Castings statiques et de réinterprétation en C++
- Upcasting et downcasting en F#