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 :

affectation et pre-incrémentation, différence de compilateur


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut affectation et pre-incrémentation, différence de compilateur
    Bonjour à tous,

    je ne parviens pas à trouver si c'est un undefined behavior ou non.
    Voici le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>
     
    int main( void )
    {
            int tab[2] = {10, 20};
            int i = 1;
            tab[i] = tab[--i];
            printf( "%d, %d\n", tab[0], tab[1] );
            return 0;
    }
    En compilant avec gcc v4.2.0 : gcc -std=c99, voici la sortie : "10, 10"
    En compilant avec xlC v11.01 ou 13.01, voici la sortie : "10, 20"
    Le système est IBM Unix AIX.

    xlC semble d'abord effectuer la pré-incrémentation puis l'affectation.

    Avez-vous des explications sur cette différence ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par défaut
    Je ne connais pas ce compilo xlC mais je dirais que gcc a raison.
    tab[i] déplace ça sur tab[1], auquel on affecte tab[--i] qui devrait faire la décrémentation de i, et donc assigner tab[0] à tab[1]
    Sur un code aussi court tu devrais comparer le code asm généré, on dirait que xlC assigne tab[1] à tab[1] avant de décrémenter i, en fait une post-décrémentation de i et non une pré-décrémentation, ce qui serait donc un bug de leur part IMO.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    Et moi je vote UB.

    D'après la norme (draft N1570), en 6.5§2 :

    If a side effect on a scalar object is unsequenced relative to either a different side effect
    on the same scalar object or a value computation using the value of the same scalar
    object, the behavior is undefined. If there are multiple allowable orderings of the
    subexpressions of an expression, the behavior is undefined if such an unsequenced side
    effect occurs in any of the orderings.
    Or il n'y a pas de sequence point au sein d'une affectation, si l'on en croit 6.8§4 (on apprendra en 6.8.3§2 qu'une affectation est un expression statement) :

    [...] Each of the following is a full expression: an initializer that is not part of a compound
    literal; the expression in an expression statement; [...] There is a sequence point between the evaluation of a full expression and the
    evaluation of the next full expression to be evaluated.
    Alors certes on peut toujours interpréter à loisir mais au mieux l'ordre d'évaluation de l'effet de bord et de l'affectation est indéterminé, c'est une raison suffisante pour bannir ce genre de chose.

  4. #4
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Ok pour l'undefined behavior et la référence à la norme.
    Je ne ferais plus jamais comme ça ;-)
    Merci !
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 845
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 845
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par dinobogan Voir le message
    En compilant avec gcc v4.2.0 : gcc -std=c99, voici la sortie : "10, 10"
    Bonjour

    De mon côté, j'ai compilé avec gcc v4.9.2 (debian8, gcc -std=c99) et j'ai eu "10, 20". Sans dec, j'aurais moi aussi parié sur "10, 10" !!!
    Surtout que si je change un seul détail...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>
     
    int main( void )
    {
            int tab[2] = {10, 20};
            int i = 1;
            tab[1] = tab[--i];
            printf( "%d, %d\n", tab[0], tab[1] );
            return 0;
    }
    ... j'obtiens bien "10, 10".
    C'est bien le fait d'intéger "i" dans la même expression que "--i" qui met la zone !!!

    Essayons maintenant de jouer avec ce "i"...

    Ici...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>
     
    int main( void )
    {
    	int tab[2] = {10, 20};
    	int i = 1;
    	tab[i=i] = tab[--i];
    	printf( "%d, %d\n", tab[0], tab[1] );
    	return 0;
    }
    ... j'obtiens de nouveau "10 20"

    Mais ici...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>
     
    int main( void )
    {
    	int tab[2] = {10, 20};
    	int i = 1;
    	int j;
    	tab[j=i] = tab[--i];
    	printf( "%d, %d\n", tab[0], tab[1] );
    	return 0;
    }
    ... j'obtiens "10 10" !!!

    Intéressant non ?
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    551
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 551
    Par défaut
    Bonjour,

    Je ne suis pas tout à fait d’accord à la réponse donnée plus haut sans pour autant dire réellement d’où vient le problème et conclure directement sur ce que dit la norme.

    Le problème est effectivement dû à une violation des règles de séquençage et d’accès ; et non a un manque de points de séquence au sein d’une affectation et cela vient plus précisément du fait que la même variable (votre variable i), est modifiée plus d'une fois au sein d’une même expression. Ainsi donc, la valeur finale de votre variable i est indéterminé au moment où l’on exécute cette instruction. La norme à ce sujet peut tout à fait spécifier l'un des deux comportements possibles tab[i]/tab[--i] , mais comme le résultat de la variable ne peut être défini/déterminer en cours d’exécution au sein de cette expression tab[i] = tab[--i] alors tout type d’instruction de la sorte (Voir également du style i= i++); est considéré comme étant un comportement indéterminé et c’est le cas dans votre exemple : la variable i est bien ambigu.

    N’oublions pas que la façon dont votre compilateur évalue la chose est totalement laissée à la discrétion des concepteurs de votre compilateur pour différentes raisons; par exemple : le langage de programmation C garantie que les opérateurs && || ? : dont l’opérateur, le plus à gauche, sera évalué en premier ; quant aux autres, cela n’est pas spécifié et donc chaque compilateur fait à sa sauce. D’ailleurs, le résultat fourni par plusieurs de vos compilateurs reflète bien la manière de comment, chaque compilateur implémente la choses.

    On peut remarquer que votre expression sur un compilateur xlC fonctionne parce que les concepteurs ont probablement défini des priorités sur l'opérateur/inséré des points de séquences volontairement sur ce genre d’expression de telles manières, à obtenir un comportement bien défini et déterminé. En clair, le compilateur xlC peut tout à fait admettre comme vous l'avez mentionné; procéder d’abord à une pré-incrémentation puis en une affectation. (peut-être à cause des règles de priorité et associativité/tout simplement parce que le compilateur a placé un point de séquence entre les deux instructions.) quand a GCC cela n'est pas le cas, il implémente les choses de manière différente de telle sorte a respecté la norme. GCC va donc émettre un avertissement s’il rencontre ce genre d’instruction pour vous dire, que vous n’avez pas séquencé les instructions et qu'on même temps vous accéder ou modifier la valeur de la variable ‘i’ et donc le résultat de ’i’ ne peut être garantie/ déterminer.

    Ceci dit, on peut également se poser la question si le compilateur xlc respecte la norme ou comment il arrive à déterminer la valeur de i sur une telle expression. la ou je rejoins @Bousk c'est sur la lecture/comparaison du code au niveau langage assembleur de votre architecture.

    À bientôt,

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

Discussions similaires

  1. Réaliser interpréteur (différence avec compilateur)
    Par Reverse_ dans le forum Générateurs de compilateur
    Réponses: 3
    Dernier message: 03/07/2017, 16h21
  2. Réponses: 4
    Dernier message: 18/03/2010, 12h48
  3. Runtime et différences entre compilateurs
    Par dfg dans le forum Langages de programmation
    Réponses: 16
    Dernier message: 08/06/2008, 17h00
  4. Réponses: 2
    Dernier message: 08/11/2007, 12h34
  5. Réponses: 4
    Dernier message: 01/02/2007, 14h13

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