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

Langage C++ Discussion :

Un bug dans le décalage ?


Sujet :

Langage C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut Un bug dans le décalage ?
    Bonjour

    Voici un petit programme dont le résultat me paraît bizarre (Code::Blocks 13.12, Windows 7)
    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>
    #include <fstream>
     
    using namespace std;
     
    int main()
    {
        unsigned n = 32 ;
     
        printf("%x, %x", 0xFFFFFFFF>>n, 0xFFFFFFFF>>32);
     
        return 0;
    }
    Résultat : ffffffff, 0

    Si on essaye d'autres valeurs, tout se passe comme si n était calculé modulo 32 avant de faire le décalage.
    32 = width of type : il y a d'ailleurs un warning à ce sujet.
    Bien sur (!), le problème disparaît si on remplace la ligne 9 par const unsigned n = 32 ;
    Une idée de ce qui se passe vraiment ?

    Merci d'avance

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 186
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 186
    Points : 17 126
    Points
    17 126
    Par défaut
    En fait, la blague, c'est que 32 est une constante de type /*signed*/ int, alors que ton n est un unsigned intet 0xffffffff est (int32)-1

    La différence est dans la propagation du bit de signe.

    avec le code suivant, tu auras normalement le meme résultat.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <cstdio>
    using namespace std;
     
    int main() {
        unsigned n = 32 ;
        printf("%x, %x", 0xF0000000>>n, 0xF0000000>>32);
        return 0;
    }
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Membre émérite
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Points : 2 724
    Points
    2 724
    Billets dans le blog
    1
    Par défaut
    Les entiers sont codé sur 32 bit, donc lorsque tu effectue un décalage, il est impossible de décalé de 32bit ou plus, c'est pourquoi un modulo est appliqué.

    en gros l'opérateur va appliquer un modulo selon cette formule:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vardroite %= sizeof(vargauche)*4;
    et ce afin d'évité un décalage de bit qui serait impossible.

    En utilisant un long long (codé sur 64bit) on repousse donc cette limite à 64 d'où le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <cstdio>
    using namespace std;
     
    int main() {
        unsigned n = 32 ;
        printf("%x, %x", (long long int)(0xFFFFFFFF)>>n, 0xF0000000>>32);
        return 0;
    }
    EDIT: mon explication ne fonctionne que si la variable de droite est une variable et non une constante, pour les constante, l'explication est donnée par mon vdd .
    Pas de solution, pas de probleme

    Une réponse utile (ou +1) ->
    Une réponse inutile ou pas d'accord -> et expliquer pourquoi
    Une réponse à votre question


  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    Bonjour
    Merci à tous pour vos réponses.

    @ eternel (j'ai légèrement modifié mon post pendant ta réponse, mais cela ne change pas grand chose).
    32 est une constante de type*/*signed*/*int, alors que ton n est un*unsigned*int
    Si on remplace la ligne 9 par int n = 32 ;, le problème subsiste.
    #include <cstdio>
    Cette modification ne change rien.

    @ skeud
    Les entiers sont codé sur 32 bit, donc lorsque tu effectue un décalage, il est impossible de décalé de 32bit ou plus
    Pourtant cela marche très bien avec la valeur numérique (ou une constante) : on peut même remplacer 32 par une valeur plus grande.
    pour les constante, l'explication est donnée par mon vdd
    vdd : késako ?

    @ gl
    The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.
    Là, je crois que tout est dit ! Juste un bémol : avec un tel comportement, un simple warning est-il suffisant ?

    Cordialement

  5. #5
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    C'est un comportement indéfini :

    The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.
    A partir de ce moment, il ne sert à rien de chercher une explication logique du comportement sur les règles de promotion, la gestion de dépassement, etc. à partir du langage. L'implémentation est en droit de faire ce qu'elle veut (y compris avec un comportement aléatoire), la documentation du compilateur peut éventuellement décrire le comportement de ce compilateur dans ce cas, mais ce n'est pas extrapolable.

    Pourquoi, il y a une différence dans les deux cas ? Car dans un cas tu as une constante défini à la compilation pas dans l'autre et donc pas le même code généré, et le comportement indéfini "à la compilation" n'est pas le même qu'un runtime avec le compilateur utilisé ici.
    Sur la version de gcc que j'ai sous la main, en déclarant n const, on retrouve le même comportement qu'en utilisant la constante littéral.

  6. #6
    Membre émérite
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Points : 2 724
    Points
    2 724
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par serge17 Voir le message
    vdd : késako ?
    voisin du dessus ^^.
    Pas de solution, pas de probleme

    Une réponse utile (ou +1) ->
    Une réponse inutile ou pas d'accord -> et expliquer pourquoi
    Une réponse à votre question


  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    (suite)

    @ skeud
    vdd = voisin du dessus.
    Je prends bonne note !

    @ gl Le décalage se comporte comme tu le dis et on n'y peut pas grand chose. Mais je ne comprends pas la logique de l'implémentation.
    Le résultat attendu est clairement 0 : si on fait une boucle avec l'instruction LSR (assembleur), le résultat va être nul à partir d'un certain rang. C'est d'ailleurs ce qui se passe avec les valeurs littérales ou les constantes. Quel est l'intérêt de faire différemment avec les variables ?

    D'autre part, utiliser une variable négative ne peut provenir que d'une erreur de programmation indétectable à la compilation. On devrait avoir une procédure du genre de celle utilisée pour les divisions par 0 et non « an undefined behavior » : difficile de débuguer un programme qui fait n'importe quoi on ne sait où !

    J'ai découvert ce comportement par hasard. Mon programme (pas le ECM de mon post !) fonctionnait correctement pour toutes les valeurs testées jusqu'à ce que j'essaye 32 : un coup de bol !

    En tout cas, merci à tous

    Je passe en résolu (mais vous pouvez toujours ajouter un petit mot !)

    Cordialement

  8. #8
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par serge17 Voir le message
    Quel est l'intérêt de faire différemment avec les variables ?
    Potentiellement par simplicité. Le compile-time peut faire des hypothèses que le runtime ne peut pas.

    Citation Envoyé par serge17 Voir le message
    D'autre part, utiliser une variable négative ne peut provenir que d'une erreur de programmation indétectable à la compilation. On devrait avoir une procédure du genre de celle utilisée pour les divisions par 0 et non « an undefined behavior » : difficile de débuguer un programme qui fait n'importe quoi on ne sait où !
    Ici le souci n'est pas l'utilisation d'une variable négative (qui est aussi un UB sur le second opérande mais implementation-defined sur le premier) mais d'un décalage plus grand que la taille.

    Pourquoi ne pas imposer une erreur ? Pour permettre au compilateur d'avoir une implémentation efficace sur certaine plateforme, lui permettre de proposer une implémentation particulière (documenté dans sa doc et potentiellement configurable) pertinente dans son domaine d'utilisation, laisser la porte ouverte à certaines optimisations, des comportements pré-existants sur lesquels on n'a pas voulu revenir, etc.
    En pratique, les UB sont un choix volontaire et réfléchis.

    Si tu veux détecter ces erreurs en phase de debug, il existe assert() dont c'est clairement le rôle.

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    Merci gl pour toutes ces précisions

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

Discussions similaires

  1. Bug dans le TCheckListBox ?
    Par Tardiff Jean-François dans le forum Composants VCL
    Réponses: 6
    Dernier message: 04/11/2004, 09h39
  2. Bug dans les expressions régulières ?
    Par SergioF dans le forum Linux
    Réponses: 8
    Dernier message: 12/05/2004, 16h14
  3. [PROPERTIES] Bug dans java.util.Properties ?
    Par mathieu dans le forum Collection et Stream
    Réponses: 6
    Dernier message: 28/04/2004, 16h11
  4. bug dans une base Access
    Par bizouard dans le forum Access
    Réponses: 5
    Dernier message: 29/12/2003, 13h41

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