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 :

const_cast<int*>, modifier une constante


Sujet :

C++

  1. #1
    Membre éclairé
    Inscrit en
    Janvier 2007
    Messages
    293
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 293
    Par défaut const_cast<int*>, modifier une constante
    Bonjour

    Voilà je cherche à modifier la valeur d'une constante à travers un const_cast.

    j'utilise le code suivant :

    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 <iostream>
     
    using namespace std;
     
    int main ()
    {
       const int constvar = 33;
     
       const int* ptr_c = &constvar;
       int* ptr = NULL;
     
       ptr = const_cast<int*> (ptr_c);
     
       *ptr = 66;
     
       cout << constvar;
     
       return EXIT_SUCCESS;
    }
    normalement à l'execution constvar devrait avoir la valeur 66, pourtant elle garde la valeur 33

    Merci

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    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 395
    Par défaut
    Il est possible que constvar soit stocké dans une zone mémoire en lecture seule, mais ce serait plus du genre à planter.

    Je pense plutôt qu'il y a une optimisation, et que gcc suppose que constvar est égal à 33 et donc, ne la re-lit même pas.
    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 émérite
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Par défaut
    faut avoir de sérieuses raisons pour vouloir faire ça..

  4. #4
    Membre chevronné

    Inscrit en
    Août 2007
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 300
    Par défaut
    Je pense aussi qu'il s'agit d'un problème d'optimisation... le problème ne se pose pas avec d'autres types que des entiers, et si on met "volatile int" ça marche.

    C'est tout de même curieux.

    J'ai lu qu'il y a beaucoup de problèmes actuellement dans le modèle mémoire de C++, et que c'est en cours de redéfinition pour C++0x pour préciser comment les optimisations peuvent être faites (pour prendre en compte les optimisations agressives, en particulier les conflits de cache entre cœurs).

    Je ne suis pas familier de ces problèmes, et je dois dire que ce genre de comportement indéfini est plutôt perturbant.

  5. #5
    Membre émérite

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Par défaut
    En quoi est-ce curieux ? Ce n'est pas du C++ valide, ça peut afficher 33 comme reformater le disque dur.

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Par défaut
    Citation Envoyé par ac_wingless Voir le message
    Je ne suis pas familier de ces problèmes, et je dois dire que ce genre de comportement indéfini est plutôt perturbant.
    ce qui est perturbant c'est ce que tu veux faire

  7. #7
    Membre éclairé
    Avatar de gb_68
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2006
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 232
    Par défaut
    Une variable const int peut être directement remplacée par sa valeur dans le code, si elle est connue à la compilation, ce qui permet notamment de les utiliser pour définir un tableau static (remplaçant par exemple certains #define)
    ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    {
        // #define Taille 10
        // avantage : la portée peut être limitée
        const int Taille = 10;
        int Tab[Taille];
        ...
    }
    Et le compilateur peut même ne pas l'allouer physiquement si ce n'est pas nécessaire.
    Par analogie, une fonction inline peut être étendue ou pas (code pas disponible, appel récursif ...). Si tu prend son pointeur et que tu "hook" la fonction (en remplaçant le début de son code -- après éventuellement fait sauté la protection de la mémoire),
    tu n'impacteras évidemment pas les endroits où elle a été "inlinée".

  8. #8
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Il est possible que constvar soit stocké dans une zone mémoire en lecture seule, mais ce serait plus du genre à planter.

    Je pense plutôt qu'il y a une optimisation, et que gcc suppose que constvar est égal à 33 et donc, ne la re-lit même pas.
    Non, constvar n'est pas en lecture seule. Par contre, le compilateur considère qu'il s'agit d'une constante intégrale - donc chaque fois qu'il y est fait référence dans le code, elle remplace l'identifiant par la valeur. Le fait que l'adresse de la constante existe ne signifie pas que la constante est modifiable via son adresse - seulement qu'il existe une zone mémoire ou la valeur de la constante est stockée.

    Ce programme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <iostream>
     
    int main()
    {
    	const int cvar = 33;
     
    	int* var = const_cast<int*>(&cvar);
    	*var = 66;
     
    	std::cout << "pointers - var: " << var  << " - &cvar: " << &cvar << std::endl;
    	std::cout << "values   - var: " << *var << " -  cvar: " << cvar << std::endl;
     
    	return 0;
    }
    Qui affiche (compilé avec VC++ 2005) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    pointers - var: 0012FF60 - &cvar: 0012FF60
    values   - var: 66 -  cvar: 33
    Le code assembleur généré est le suivant:
    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
     
    // la seconde partie du deuxième appel à std::cout: 
    x00414186  mov         esi,esp 
    x00414188  mov         eax,dword ptr [__imp_std::endl (41A308h)] 
    x0041418D  push        eax  
    x0041418E  mov         edi,esp 
    x00414190  push        21h    /// <------ 33 :)
    x00414192  push        offset string " -  cvar: " (417710h) 
    x00414197  mov         ebx,esp 
    x00414199  mov         ecx,dword ptr [var] 
    x0041419C  mov         edx,dword ptr [ecx] 
    x0041419E  push        edx  
    x0041419F  push        offset string "values   - var: " (4176FCh) 
    x004141A4  mov         eax,dword ptr [__imp_std::cout (41A304h)] 
    x004141A9  push        eax
    Par contre, si cvar est une constante globale, elle sera alors mise dans le segment rodata (et sera donc en read-only). Ce programme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <iostream>
     
    const int cvar = 33;
     
    int main()
    {
    	int* var = const_cast<int*>(&cvar);
    	*var = 66;
     
    	std::cout << "pointers - var: " << var  << " - &cvar: " << &cvar << std::endl;
    	std::cout << "values   - var: " << *var << " -  cvar: " << cvar << std::endl;
     
    	return 0;
    }
    génère une exception 0xC0000005:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    First-chance exception at 0x004114d8 in cvar.exe: 0xC0000005: Access violation writing location 0x004176fc.
    Avant de terminer, je voudrais insister sur un point: ce n'est la que le comportement d'un compilateur parmi d'autres. Le standard actuel est explicite sur le sujet (section 7.1.5.1 [dcl.type.cv], §4):
    ... any attempt to modify a const object during its lifetime (...) results in undefined behavior.
    Pour autant, si votre compilateur se met à formater votre disque dur, je n'ai qu'un seul conseil à donner : changez-en.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  9. #9
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    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 395
    Par défaut
    Moi, j'ai préféré une DS9K : Chaque fois que j'ai un comportement indéfini, ça balance un missile nucléaire quelque part dans le monde.
    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.

  10. #10
    Membre éclairé
    Inscrit en
    Janvier 2007
    Messages
    293
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 293
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Avant de terminer, je voudrais insister sur un point: ce n'est la que le comportement d'un compilateur parmi d'autres. Le standard actuel est explicite sur le sujet (section 7.1.5.1 [dcl.type.cv], §4):

    Oki, sur mon vieux livre il utilisaient borland c++ et ça marchait, mais bon je trouvais ça un peu tordu de pouvoir modifier une constante.

    Merci

  11. #11
    Membre chevronné

    Inscrit en
    Août 2007
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 300
    Par défaut
    une petite recherche google intéressante:

    exhortae, ce lien contient une discussion exactement sur ce sujet, en particulier comment le langage D distingue entre les deux forms de const mélangées en C++,
    - le "const int", qui définit l'invariance réelle d'un objet (il peut par exemple être implémenté en ROM)
    - et le qualificateur d'accès au travers du pointeur "const int*", qui dit seulement la manière dont on voit la zone pointée (les droits d'accès sont alors modifiables par const_cast).
    ce que l'auteur nomme "const as a storage class, and const as a type attribute."
    Dans votre exemple, le const_cast s'applique non pas à la classe de stockage, mais au droit d'accès.

    Apparemment, en D, on peut distinguer ces deux concepts, alors qu'en C++, la distinction se fait selon que le qualificateur const est appliqué ou non au premier niveau d'une déclaration.

  12. #12
    Membre éclairé
    Inscrit en
    Janvier 2007
    Messages
    293
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 293
    Par défaut
    Citation Envoyé par ac_wingless Voir le message
    une petite recherche google intéressante:

    exhortae, ce lien

    Merci pour le lien

  13. #13
    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 ac_wingless Voir le message
    Je pense aussi qu'il s'agit d'un problème d'optimisation... le problème ne se pose pas avec d'autres types que des entiers, et si on met "volatile int" ça marche.
    Avec la version que tu utilises de ton compilateur, peut-être (mais es-tu sûr d'avoir testé tous les cas?).

    Avec d'autres compilateurs, ce que tu appeles "le problème" peut exister avec d'importe quel type.

    Citation Envoyé par ac_wingless Voir le message
    C'est tout de même curieux.
    En quoi?

    Citation Envoyé par ac_wingless Voir le message
    J'ai lu qu'il y a beaucoup de problèmes actuellement dans le modèle mémoire de C++, et que c'est en cours de redéfinition pour C++0x pour préciser comment les optimisations peuvent être faites (pour prendre en compte les optimisations agressives, en particulier les conflits de cache entre cœurs).
    Il n'y a aucun problème avec le "modèle mémoire" à cause du fait que l'on ne puisse pas modifier une constante. (En C non plus on ne peut pas modifier une constante. Est-ce que le modèle mémoire va être modifié pour autant?)

    Tu veux probablement parler de l'introduction du multithread en C++, et du fait que le modèle mémoire est redéfini par rapport à l'exécution de plusieurs threads. Ce qui doit définir ce que les implémentations peuvent faire en multithread (donc les optimisations permises), mais n'a pas pour but de préciser les optimisations possibles sur du code mono-thread.

    Sinon, le multi-core n'est juste du multi-processeur - et encore pas tout à fait : il y a deux espèces différentes de "multi-core" (différents au niveau du partage du cache) correspondant plus ou moins exactement au multi-processeur classique, d'après ce que j'ai compris.

    Les conflits de cache sont gérés automatiquement au niveau matériel, et c'est parfaitement transparent (sauf au niveau des performances). Le programmeur n'a pas affaire au cache, même au niveau assembleur, sauf dans les cas où une donnée est accédée derrière le dos du cache : accès directe à la mémoire par un périphérique, et modification du code exécutable.

    Citation Envoyé par ac_wingless Voir le message
    Je ne suis pas familier de ces problèmes, et je dois dire que ce genre de comportement indéfini est plutôt perturbant.
    Qu'est-ce que tu essaies de faire, au final?

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 21/05/2010, 11h56
  2. Modifier une chaîne d'un pointeur constant
    Par oranoutan dans le forum C
    Réponses: 7
    Dernier message: 25/05/2007, 16h32
  3. Partage d'une constante entre 2 fichiers en C
    Par elsargento dans le forum C
    Réponses: 6
    Dernier message: 29/09/2003, 22h17
  4. Modifier une partion ntfs avec Disk druid
    Par Sébastien dans le forum Administration système
    Réponses: 5
    Dernier message: 24/09/2003, 14h58

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