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 :

[Transtypage] encore une erreur static_cast


Sujet :

C++

  1. #1
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut [Transtypage] encore une erreur static_cast
    Je ne comprends pas l'usage de static_cast. Pourquoi un code aussi simple que celui-ci est refusé ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    		int *pi=new int(25);
    		long *pl=static_cast<long *>(pi);
    Convertir un pointeur en un autre pointeur, quel qu'il soit, devrait être accepté par static_cast, c'est bien son but quand même ?

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Ben non, caster des pointeurs de types sans relation, c'est le rôle du reinterpret_cast.
    Static_cast peut caster un entier en long, par contre.

  3. #3
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Convertir un pointeur en un autre pointeur, quel qu'il soit, devrait être accepté par static_cast, c'est bien son but quand même ?
    Il n'y a *aucun* cast qui permette ceci, même le cast C-style (le plus permissif) ne le permet pas.

    Les casts C++ existent pour ne permettre que très peu de choses et ainsi éviter les erreurs.

    C-style cast : conversion entre deux pointeurs vers des objets, conversion entre deux pointeurs vers des fonctions, conversion entre pointeur et entier, conversion entre différents types d'entiers et de flottants.
    reinterpret_cast : même chose que le C-style cast, sauf que const et volatile ne peuvent pas être modifiés pour les conversions entre pointeurs vers des objets.
    const_cast : conversion entre deux pointeurs vers des objets dont seuls les qualifiants const et volatile peuvent varier.
    static_cast : conversion entre différents types d'entiers et de flottants, et conversion entre différents pointeurs vers des objets si le type cible est dérivé ou si l'entrée est void*. Ne peut bien sûr pas modifier const et volatile.

    Après il y a aussi les conversions explicites et implicites, qui sont à utiliser de préférence si elles suffisent.
    Le C-style cast est à éviter, au moins pour les casts entre pointeurs vers des objets.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Euh... Qu'est-ce que le C-Style cast ne parmet pas, à part les casts entre pointeurs de fonction et pointeurs vers n'importe quoi d'autre?

  5. #5
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Si j'ai bien compris, ceci est un classement du plus permissif au moins permissif:
    C-style
    reinterpret_cast
    static_cast
    const_cast

    J'utilise souvent le C-style. Je voulais justement me défaire de mes habitudes C, ainsi reinterpret_cast est "l'équivalent" C++ du C-style et non pas static_cast comme je le croyais.
    Merci.

  6. #6
    screetch
    Invité(e)
    Par défaut
    le C-cast n'est pas equivalent au reinterpret_cast, il y a de subtiles différences...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    #include <cstdio>
     
    class A;
    class B;
    class C;
     
    class A
    {
    	int offset;
    };
     
    class Aprime
    {
    	int offset2;
    };
     
    class B : public Aprime, public A
    {
    	int value;
    };
     
    static void testB(A* a)
    {
    	B* b1 = (B*)a;
    	B* b2 = reinterpret_cast<B*>(a);
    	B* b3 = static_cast<B*>(a);
    	printf("a : %p\nC-cast : %p\nreinterpret_cast : %p\nstatic_cast : %p\n", a, b1, b2, b3);
    }
     
    static void testC(A* a)
    {
    	C* c1 = (C*)a;
    	C* c2 = reinterpret_cast<C*>(a);
    	printf("a : %p\nC-cast : %p\nreinterpret_cast : %p\nstatic_cast : unavailable\n", a, c1, c2);
    }
     
    class C : public Aprime, public A
    {
    	int value;
    };
     
    int main()
    {
    	A* b = new B;
    	A* c = new C;
     
    	testB(b);
    	testC(c);
    }
    ici, il y a double heritage, un B est donc un A et un Aprime
    Aprime etant le premier

    les données d'un B sont donc celles d'un A et d'un Aprime
    dans l'ordre, on a les données de Aprime puis celle de A
    donc, si on veut considérer un B comme un Aprime, il suffit de mettre le pointeur sur les données de Aprime
    si on veut considérer un B comme un A, il faut mettre le pointeur sur les données de A (qui sont apres Aprime)

    donc, un cast de B en A devrait renvoyer un pointeur sur les données de A qui sont a l'interieur de B, pas sur le debut de B (j'espere me faire bien comprendre)
    c'est l'opération correcte a faire.

    Ici, ce programme donne le résultat des differents cast :
    - un reinterpret_cast ne fera jamais cette operation, il va changer un pointeur sur B en un pointeur sur A, mais en fait ce pointeur pointera sur Aprime. Il a fait ce qu'on lui a demandé, REINTERPRETER le pointeur en autre chose
    - un static_cast fera la bonne opération lui, a condition de savoir comment faire un pointeur sur B a partir d'un pointeur sur A, c'est a dire avoir la définition des classes B et A et Aprime. Le static_cast echouera pour C car il ne sait pas comment faire un pointeur sur C a partir d'un pointeur sur A.
    - Le C-cast va marcher des fois, et des fois pas; des fois il va faire comme reinterpret_cast et des fois comme static_cast
    Lorsque le c-cast connait la définition des classes, il fait la bonne opération
    lorsqu'il ne connait pas (dans le cas du C plus haut, il ne voit pas la definition de C) alors un c-cast fera comme un reinterpret_cast.


    C-cast c'est la mort lente du développeur. Utilisez static_cast, evitez reinterpret_cast.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Le C-style cast n'est pas un équivalent du reinterpret_cast<>. Sans aller jusqu'au subtilités soulignées par screetch, il correspond plus à un reinterpret_cast<> plus un const_cast<>. Cela le rend extrêmement dangereux, à bannir dès que des pointeurs const sont en jeu.

  8. #8
    screetch
    Invité(e)
    Par défaut
    a bannir pour tous les pointeurs a priori, const ou non const =)

    a garder pour changer un int en un float, a la rigueur... mais un bon veux checked_numcast<>() fait aussi beaucoup mieux

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    #include <cassert>
    template< typename R, typename T >
    R checked_numcast(T value)
    {
    	R r = (R)value;
    #ifdef _DEBUG
    	assert((T)r == value);
    #endif
    	return r;
    }
     
    int main()
    {
    	float i = 1.0f;
    	int i2 = checked_numcast<int>(i);
    	i = 1.2f;
    	i2 = checked_numcast<int>(i);
    }

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    À quoi sert exactement ton #if ?

  10. #10
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Je pense que pour ce que je veux, je dois utiliser reinterpret_cast, c'est-à-dire que la valeur du pointeur reste identique quelque soit le cast (donc la zone mémoire pointée):
    char *cp=new char[1000];
    void *vp=cp;
    UneStructure *sp=reinterpret_cast<UneStructure>(vp);
    UneClasse *lp=reinterpret_cast<UneClasse>(sp);

    Quant au C-style, si le résultat est vraiment du genre une-fois-je-static-une-fois-je-reinterpert, c'est plutôt dangeureux. Heureusement que je ne m'aventure que rarement (jamais ?) dans l'héritage multiple.

  11. #11
    screetch
    Invité(e)
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    À quoi sert exactement ton #if ?
    a plus rien, je voulais le mettre pour avoir une fonction d'erreur personnalisée pis j'ai été attaqué par cette fourberie qu'on appelle la flemme, alors j'ai mis assert a la place. pis, toujours sous le coup de la flemme, j'ai pas retiré le #if. vala.

  12. #12
    screetch
    Invité(e)
    Par défaut
    Citation Envoyé par camboui Voir le message
    Je pense que pour ce que je veux, je dois utiliser reinterpret_cast, c'est-à-dire que la valeur du pointeur reste identique quelque soit le cast (donc la zone mémoire pointée):
    char *cp=new char[1000];
    void *vp=cp;
    UneStructure *sp=reinterpret_cast<UneStructure>(vp);
    UneClasse *lp=reinterpret_cast<UneClasse>(sp);

    Quant au C-style, si le résultat est vraiment du genre une-fois-je-static-une-fois-je-reinterpert, c'est plutôt dangeureux. Heureusement que je ne m'aventure que rarement (jamais ?) dans l'héritage multiple.
    oui, c'est ca, c'est un reinterpret_cast cela.

  13. #13
    Membre actif Avatar de g0up1l
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    341
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 341
    Points : 294
    Points
    294
    Par défaut
    juste pour info : à noter le qui te permet de savoir si ton transtypage s'est bien passé ou non.

  14. #14
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Ok, merci.
    On va dire que c'est résolu

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Encore une erreur sql
    Par Paulinio86 dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 17/06/2015, 14h24
  2. Encore une erreur de da.Update(ds, "blabla")
    Par Biggy30 dans le forum Accès aux données
    Réponses: 1
    Dernier message: 01/04/2014, 23h57
  3. [MySQL] (Encore une) Erreur de syntaxe MySQL
    Par n1n0x dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 14/04/2008, 18h30
  4. Encore une erreur de compilation
    Par MarioNoFearS dans le forum C++
    Réponses: 3
    Dernier message: 02/06/2007, 13h05
  5. [Tableaux] encore une erreur du au changement
    Par cyrill.gremaud dans le forum Langage
    Réponses: 17
    Dernier message: 15/06/2006, 09h47

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