Que veut dire casting?

18

Lors du codage dans des langages de bas niveau comme CI, trouver que la conversion signifie parfois `` réinterpréter ces octets comme s'il avait toujours été de cet autre type '' et à d'autres moments comme `` convertir cette valeur intelligemment en cet autre type ''.

Quelle est la signification originale du mot et y a-t-il une cohérence dans le moment de s'attendre à une conversion et le moment de s'attendre à une réinterprétation brute?

Alexander Torstling
la source
qu'est-ce que vous ne comprenez pas dans un article Wikipedia ? « Conversion de type , transtypage , et la contrainte sont différentes façons de, implicitement ou explicitement, la modification d' une entité d'un type de données dans un autre ... Chaque langage de programmation a ses propres règles sur la façon dont les types peuvent être convertis ... »
moucheron
La signification originale de "lancer" n'a rien à voir avec la programmation, voir ici merriam-webster.com/dictionary/cast
Doc Brown
1
Beaucoup (principalement du point de vue de la langue gérée) sur le blog d'Eric Lippert dans la catégorie des opérateurs de casting
AakashM
1
@gnat: Je ne sais pas si c'est une question sérieuse ou juste une tentative de pêche à la traîne. Mais je voudrais savoir comment va faire le compilateur: convertir, transtyper ou contraindre? Quelles sont les règles de base?
Alexander Torstling
1
@DocBrown Je pense que le terme castau sens informatique est plus similaire à la coulée au sens métallurgique, où la forme d'un métal fondu est reformée lorsqu'il est coulé dans un moule: britannica.com/EBchecked/topic/377665/metallurgy/81884/Casting
KChaloux

Réponses:

10

La diffusion en C est unique, contrairement à d'autres langages. Il n'est également jamais intelligent.

La conversion en C convertit les valeurs d'un type à un autre à l'aide de règles soigneusement définies. Si vous avez vraiment besoin de savoir, lisez la norme. Sinon, les points principaux sont:

  1. La conversion entre les types entiers conserve la valeur, si possible. Si la destination a plus de bits, cela s'élargit et est généralement sûr, mais peut impliquer une extension de signe. Si elle est plus étroite, les bits seront perdus.
  2. La conversion entre les types de pointeurs préserve la valeur du pointeur, mais les résultats sont souvent indéfinis, souvent non portables et souvent utiles pour les scénarios avancés.
  3. La conversion entre les types entiers et les pointeurs est OK si l'entier est assez grand et préserve le modèle de bits (quoi que cela puisse arriver). Si l'entier est trop petit, le résultat n'est pas défini mais n'est pas utile. En règle générale, «long» est suffisamment large pour «void *», mais aucune garantie! Les pointeurs créés de cette manière peuvent être invalides, de toutes sortes de façons intéressantes.
  4. Les conversions entre les types float et integer sont des conversions arithmétiques telles que définies par une routine de bibliothèque appropriée (avec troncature, pas d'arrondi).
  5. Vous pouvez convertir la valeur de retour d'une fonction pour l'annuler. Je n'ai jamais. Ça ne fait rien.

Certains transtypages sont appliqués implicitement, et dans certains d'entre eux, le compilateur émet un avertissement. Mieux vaut tenir compte des avertissements!

Il est préférable d'ignorer la définition du dictionnaire pour la distribution, car elle n'est pas utile. De nombreux modèles sont mieux décrits par les termes conversion ou coercition, il vaut donc la peine de les connaître également.

C ++ est BEAUCOUP plus compliqué, mais vous ne l'avez pas demandé, n'est-ce pas?

david.pfx
la source
Je m'intéresse aux règles de base, et non aux moindres détails, mais je m'intéresse à d'autres langages que C si cela aide à clarifier les choses.
Alexander Torstling
2
Ce que j'ai donné ici est aussi générique que raisonnable. Pour écrire du vrai code professionnel C / C ++ de bas niveau, les détails minuscules sont essentiels. La plupart des langues n'ont tout simplement pas ce genre de problème dans leurs conversions de types. Désolé si cela ne résout pas votre problème.
david.pfx
Sauf que la conversion de T*vers void*et retour est toujours bien définie.
Miles Rout
@Miles: En fait, la conversion de T * en n'importe quel U * et retour est nécessaire pour conserver la valeur du pointeur d'origine. Dans ma réponse, j'ai seulement dit «souvent indéfini» pour être bref, «car certains détails sont très compliqués.
david.pfx
1
@supercat: Voir n1570 S6.3.2.3. La conversion / l'aller-retour entre T *, U * et void * conserve toujours la valeur du pointeur à une seule exception près. Si un T * n'est pas correctement aligné, c'est un comportement indéfini. J'accepte votre point, mais seulement dans cette mesure.
david.pfx
2

Cette partie du dictionnaire Webster donne la bonne définition:

a: donner une forme à (une substance) en versant sous forme liquide ou plastique dans un moule et laisser durcir sans pression
b: se former par ce procédé

Ainsi, avant de lancer, votre "objet" (pas littéralement un objet OOP) est dans une forme (type) donnée. Lorsque vous le refondez, c'est "couler du béton" autour pour lui donner une nouvelle forme, c'est ce que vous faites avec la coulée. Vous avez un nombre sous forme d'entier hexagonal, et après la coulée, vous obtiendrez une chaîne en forme de rectangle.

Juha Untinen
la source
2
Aussi : "Attribuer un certain rôle à (un acteur)".
Kelly Thomas
Ouaip. Je suis sûr que c'est le meilleur. +1.
david.pfx
2

Il peut être utile de séparer les transtypages C en deux groupes:

  1. Moulages numériques - convertissez un nombre entre une représentation en une autre, en essayant de conserver la valeur. Par exemple - (int)3.1serait 3. Il existe des règles précises définissant ce qui se passe lorsque la valeur exacte ne peut pas être conservée.

  2. Casting du pointeur - Conservez l'adresse mémoire, mais changez la façon dont elle est déréférencée. Par exemple, pour float x=3.5, *(int *)&xdonnera 1080033280- cet entier est représenté par le même motif binaire qui représente le flottant 3.5.

ugoren
la source
Keep the memory address, but change the way it's dereferenced.Le déréférencement d'un pointeur avec punition de type n'est pas défini. La norme garantit uniquement que la coulée de et A *vers l' B *arrière produira la même chose A *, qui peut ne pas avoir été valable pour déréférencer en premier lieu - ou que si B *c'est un char *, elle peut être utilisée pour lire la représentation d'objet de tout type. Pour tous les autres types, le B *pointeur de déréférencement est punitif, UB et viole l'aliasing strict. Quoi qu'il en soit, même si le compilateur n'a pas mis à la poubelle l'exemple 2 ci-dessus pour cette raison, vous faites des hypothèses non transférables sur les modèles de bits
underscore_d
1
cast (v): to receive form in a mold

En C ++, les différents types de transtypages peuvent être rendus plus explicites, ce qui reinterpret_castsignifie "traiter ces octets comme s'ils étaient déjà cette autre chose". En C, vous pouvez le rendre absolument explicite en utilisant un union, le casting avec l' (type)opérateur tentera de garder le résultat numériquement équivalent, jusqu'à perte de précision.

U2EF1
la source
2
En C, les transtypages de pointeurs sont toujours réinterprétés et les transtypages de valeur conservent toujours la valeur du mieux possible. En C ++, il existe plusieurs façons d'effectuer une conversion de pointeur, c'est pourquoi il existe des types de conversion plus explicites.
Jan Hudec
La sémantique castée par pointeur C n'est pas nécessairement "réinterprétée". Il serait légitime pour un processeur qui utilise l'adressage de mots mais qui veut bien interagir avec du code basé sur des octets d'avoir un int*mot qui soit un mot et char*deux mots [avec le deuxième octet sélectionnant l'octet haut ou bas d'un mot]. La conversion d'un (int*)to (char*)nécessiterait l'ajout d'un mot supplémentaire qui devrait être la valeur qui spécifierait le premier octet du int.
supercat