IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

problème de cast


Sujet :

C++

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    134
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 134
    Par défaut problème de cast
    Bonjour,
    J'aimerais caster un nombre entier en nombre flottant.
    Je veux un cast qui conserve la signature du nombre, autrement dit que les 4 octets du nombre ne bougent pas.

    Quand je fais un reinterpret_cast<float>( 0xFFFFFFFF), mon compilateur (gcc) me sort une erreur: invalid cast from type «unsigned int" to type «float"
    Est-ce que quelqu'un a une piste?

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 392
    Par défaut
    Il faut passer par un cast de pointeurs:

    En supposant que les deux types aient la même taille:
    monUInt = *reinterpret_cast< unsigned int * >(&monFloat)
    Et dans l'autre sens: monFloat = *reinterpret_cast< float * >(&monUInt)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    134
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 134
    Par défaut
    Effectivement, ça marche, merci.
    Mais je m'étonne que le reinterpret_cast ne sache pas convertir un int en float directement.

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    410
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 410

  5. #5
    Invité
    Invité(e)
    Par défaut
    Salut Hypnocrate,

    Si tu dois faire des aller-retours entre float et unsigned int, tu peux aussi utiliser une union:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    union BitPuree
    {
      unsigned int asInt;
      float asFloat;
    };
     
    BitPuree myPuree;
    myPuree.asInt = 0xffffffff;
    float someOtherFloat = myPuree.asFloat;
    //...
    myPuree.asFloat = someProcessedFloat;
    unsigned int result = myPuree.asInt;
    Carl

  6. #6
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par 5hdumatin Voir le message
    Si tu dois faire des aller-retours entre float et unsigned int, tu peux aussi utiliser une union:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    union BitPuree
    {
      unsigned int asInt;
      float asFloat;
    };
     
    BitPuree myPuree;
    myPuree.asInt = 0xffffffff;
    float someOtherFloat = myPuree.asFloat;
    //...
    myPuree.asFloat = someProcessedFloat;
    unsigned int result = myPuree.asInt;
    Comportement indéfini, la manière correcte est d'utiliser memcpy.

  7. #7
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 962
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 962
    Par défaut
    Voe,
    Citation Envoyé par corrector Voir le message
    Comportement indéfini, la manière correcte est d'utiliser memcpy.
    Pourquoi comportement indéfini ?

    Sous réserve que float et unsigned int aient la même taille, le comportement est précisément celui attendu.

    Et le problème éventuellement posé si les tailles sont différentes se retrouvera lors de l'utilisation de memcpy.

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    410
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 410
    Par défaut
    oui de même taille sur certaines architectures... mais et le codage?

  9. #9
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut mésusage d'une union
    Citation Envoyé par droggo Voir le message
    Pourquoi comportement indéfini ?
    Comportement indéfini parce que le membre de l'union que tu lis ne correspond pas à celui que tu as écris en dernier (et aucun des deux n'est une structure).

    Citation Envoyé par droggo Voir le message
    Sous réserve que float et unsigned int aient la même taille, le comportement est précisément celui attendu.
    Ah bon, où ce comportement est-il défini?

    Dans la norme (pour un programme portable)?

    Dans la doc de ton compilateur (pour un programme non-portable)?

  10. #10
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 962
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 962
    Par défaut
    Fei,
    Citation Envoyé par corrector Voir le message
    Comportement indéfini parce que le membre de l'union que tu lis ne correspond pas à celui que tu as écris en dernier (et aucun des deux n'est une structure).
    C'est exactement ce que tu obtiendrais en utilisant memcpy comme tu l'as proposé, et que ce soit une structure ou pas n'a rien à voir là-dedans.

  11. #11
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par droggo Voir le message
    Fei,

    C'est exactement ce que tu obtiendrais en utilisant memcpy comme tu l'as proposé, et que ce soit une structure ou pas n'a rien à voir là-dedans.
    Tu es sûr? Pourquoi le comportement serait indéfini?

    Et comment éviter le comportement indéfini alors?

  12. #12
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par droggo Voir le message
    C'est exactement ce que tu obtiendrais en utilisant memcpy comme tu l'as proposé, et que ce soit une structure ou pas n'a rien à voir là-dedans.
    Pas sûr. J'ai pas été faire une exégèse mais à mon avis la lecture d'un champs autre que le dernier écrit d'une union me semble être un comportement indéfini même dans le cas où les deux champs sont de même type tandis que le résultat de memcpy n'est du comportement indéfini que une lecture a lieu par après et si le motif de bits écrits n'est pas un motif valide pour le type lu (raisonnement: un memcpy vers un tableau d'unsigned char est bien défini, un memcpy depuis un tel tableau l'est aussi si le motif de bits copié est un motif valide et je ne vois pas de raison pour laquelle avoir la source d'un autre type poserait problème).

    En passant, corrector, tu as une partie de la réponse que je ne t'ai jamais donnée sur la manière d'utiliser de manière conforme certaines garanties en matière de représentation.

  13. #13
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 962
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 962
    Par défaut
    Fio,
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Pas sûr. J'ai pas été faire une exégèse mais à mon avis la lecture d'un champs autre que le dernier écrit d'une union me semble être un comportement indéfini même dans le cas où les deux champs sont de même type tandis que le résultat de memcpy n'est du comportement indéfini que une lecture a lieu par après et si le motif de bits écrits n'est pas un motif valide pour le type lu (raisonnement: un memcpy vers un tableau d'unsigned char est bien défini, un memcpy depuis un tel tableau l'est aussi si le motif de bits copié est un motif valide et je ne vois pas de raison pour laquelle avoir la source d'un autre type poserait problème).

    En passant, corrector, tu as une partie de la réponse que je ne t'ai jamais donnée sur la manière d'utiliser de manière conforme certaines garanties en matière de représentation.
    Dans le cas dont nous parlons, c'est exactement équivalent à copier les données brutes d'une variable à l'autre avec memcpy, et c'est également strictement équivalent (quant au résultat) à la méthode proposée par Medinoc, qui est celle que je préfère :
    Citation Envoyé par Médinoc Voir le message
    Il faut passer par un cast de pointeurs:
    En supposant que les deux types aient la même taille:
    monUInt = *reinterpret_cast< unsigned int * >(&monFloat)
    Et dans l'autre sens: monFloat = *reinterpret_cast< float * >(&monUInt)
    à quoi la réponse a été
    Citation Envoyé par Hypnocrate Voir le message
    Effectivement, ça marche, merci.
    Mais je m'étonne que le reinterpret_cast ne sache pas convertir un int en float directement.

    Dans tous les cas, il faudrait pouvoir garantir que toute valeur binaire valide pour un des types l'est aussi pour l'autre, ce qui n'est d'ailleurs pas le cas entre un unsigned int et un float, puisque on risque de tomber sur des NAN et autres choses.
    Mais la question était un cast entre ces 2 types, ce n'est pas à moi de décider de sa validité.

  14. #14
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par corrector Voir le message
    Comportement indéfini, la manière correcte est d'utiliser memcpy.
    Après réflexion, bien que le code fonctionne en pratique, je crois qu'effectivement le comportement est indéfini d'après le standard (pas lu, mais cela me rappelle bien quelque chose). Au temps pour moi.

    Carl

  15. #15
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par Hypnocrate Voir le message
    Mais je m'étonne que le reinterpret_cast ne sache pas convertir un int en float directement.
    Pourquoi? Tu ne peux pas non plus écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    const int ci = 3;
    int i = const_cast<int> (ci);
    ni
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Base { virtual ~Base(); };
    class Derived : public Base {};
     
    Base b;
    Derived d = static_cast<Derived> (b);
    ni
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Derived d = dynamic_cast<Derived> (b);

  16. #16
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par droggo Voir le message
    la méthode proposée par Medinoc, qui est celle que je préfère :
    Le comportement est indéfini à cause de :
    Citation Envoyé par N2315, 3.10 Lvalues and rvalues [basic.lval]/15
    If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined
    • the dynamic type of the object,
    • a cv-qualified version of the dynamic type of the object,
    • a type similar (as defined in 4.4) to the dynamic type of the object,
    • a type that is the signed or unsigned type corresponding to the dynamic type of the object,
    • a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
    • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union),
    • a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
    • a char or unsigned char type.
    On accède à un unsigned int par un float, et ça n'est clairement pas un des cas de la liste.

    Le comportement est encore plus indéfini parce qu'il n'y a rien qui t'indiques ce que vaut le résultat de reinterpret_cast, et si cette valeur est déréférençable.

  17. #17
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Pas sûr. J'ai pas été faire une exégèse mais à mon avis la lecture d'un champs autre que le dernier écrit d'une union me semble être un comportement indéfini même dans le cas où les deux champs sont de même type
    Là, j'ai du mal à te suivre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    union {
    	int a, b;
    } u;
    int *pa = &u.a, *pb = &u.b;
    *pa = 1;
    cout << *pb;
    Est-ce que ce code a un comportement indéfini? Pourtant pa = pb!

  18. #18
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par droggo Voir le message
    Dans le cas dont nous parlons, c'est exactement équivalent à copier les données brutes d'une variable à l'autre avec memcpy,
    Référence?

    Le problème n'est pas la représentation en mémoire ou un formalisme poussé à l'absurde, c'est savoir que ce que les optimiseurs peuvent se permettre de faire. Mon expérience est qu'ils utilisent de plus en plus ce genre de liberté.

    et c'est également strictement équivalent (quant au résultat) à la méthode proposée par Medinoc, qui est celle que je préfère:

    à quoi la réponse a été
    Ca marche
    Ca marche ici et maintenant n'a jamais, en C++, été le moindre commencement de preuve que c'est sensé marcher.


    Citation Envoyé par corrector Voir le message
    Là, j'ai du mal à te suivre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    union {
    	int a, b;
    } u;
    int *pa = &u.a, *pb = &u.b;
    *pa = 1;
    cout << *pb;
    Est-ce que ce code a un comportement indéfini? Pourtant pa = pb!
    Non, mais je crois que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    u.a = 1;
    cout << u.b;
    en a bien un.

    Ca va naturellement fonctionner comme on le désire jusqu'au moment où il y en a un qui remarque que prendre en compte que u.a et u.b ne peuvent pas être des alias et les assigner à des registres différents permet de gagner 10% sur un des benchs de SPEC.

  19. #19
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Le problème n'est pas la représentation en mémoire ou un formalisme poussé à l'absurde,
    un formalisme poussé à l'absurde me permettrait de raisonner sur les programmes, et de me convaincre de certaines choses sans hand-waving intensif.
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Non, mais je crois que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    u.a = 1;
    cout << u.b;
    en a bien un.
    Mais pour moi ils sont exactement équivalents! (Là je suis perdu.)

    Ou alors je ne saisis pas la sémantique des pointeurs sur membres d'union. (On dirait que les unions sont définies dans un langage qui n'a pas de pointeurs.)

    En plus, j'étais en train de me dire que mon argument pa = pb ne tenait pas, pa et pb ne sont pas intentionnellement équivalents, comme &x[0][1]+1 et &x[1][0] (pour 'int x[2][2];'). (J'allais poster une note à ce sujet... à l'instant.)
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Ca va naturellement fonctionner comme on le désire jusqu'au moment où il y en a un qui remarque que prendre en compte que u.a et u.b ne peuvent pas être des alias et les assigner à des registres différents permet de gagner 10% sur un des benchs de SPEC.
    Et après ça va râler pendant des mois sur la mailing-list.

  20. #20
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par corrector Voir le message
    un formalisme poussé à l'absurde me permettrait de raisonner sur les programmes, et de me convaincre de certaines choses sans hand-waving intensif.
    Si tu veux plus de rigueur, tu sais où trouver les langages qui l'offrent.

    Mais pour moi ils sont exactement équivalents! (Là je suis perdu.)
    Pour argumenter réellement, il faudrait que je retourne voir précisément les textes, parce qu'ici je raisonne plus sur le modèle que je me suis construit que sur les textes -- et mon modèle a volontairement tendance à être trop prudent.

    Ou alors je ne saisis pas la sémantique des pointeurs sur membres d'union. (On dirait que les unions sont définies dans un langage qui n'a pas de pointeurs.)
    Le problème est plutôt que le modèle dont le C++ a hérité du C hésite entre deux niveaux d'abstractions.

    Et après ça va râler pendant des mois sur la mailing-list.
    Ce n'est pas l'activité sur les mailing lists qui me gène, c'est le temps passé à trouver la source d'un problème qui n'apparait que dans la version optimisée sur la plateforme la moins utilisée.

Discussions similaires

  1. [CASTS]problème de cast de Time
    Par DeVoN dans le forum Langage
    Réponses: 7
    Dernier message: 22/02/2006, 17h24
  2. [JDBC Driver][JSTL] Problème de cast de données
    Par GyLes dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 27/09/2005, 10h00
  3. problème de cast!
    Par LaseLiep dans le forum Langage
    Réponses: 3
    Dernier message: 03/06/2005, 09h30
  4. Problème de cast/serialization/externalization ?
    Par Linlin dans le forum CORBA
    Réponses: 1
    Dernier message: 06/12/2004, 16h46
  5. [C#] Problème de casting de @IDENTITY
    Par bilb0t dans le forum Accès aux données
    Réponses: 7
    Dernier message: 03/09/2004, 09h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo