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 floatpeut 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_valueen 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 :

  1. floatà des intcauses troncature , à savoir le retrait de la partie décimale.
  2. doubleà floatcause de l' arrondissement des chiffres.
  3. longà intcause 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, ydans ce cas, est compatible avec le type de son entité cible, xdans 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 yest conforme au type de xsi la classe sur laquelle yest basée est un descendant de celle sur laquelle xest 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_STRINGest l'alias compatible Eiffel pour System.String). Parce que System.Stringn'est pas conforme à STRING_8, l'affectation ci-dessus n'est valide que si elle est System.Stringconvertie en STRING_8.

La classe Eiffel STRING_8a une procédure de conversion make_from_cilpour 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_8classe :

    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_stringest construit comme un nouvel objet de type STRING_8avec 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_8contient également une requête de conversion to_cilqui produira un à System.Stringpartir 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 asmot - 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

Les références

Liens externes