2016-03-05 1 views
-4

Le code ci-dessous affiche des résultats différents lorsqu'il est compilé et exécuté sur Code :: Blocks.Requête du débutant sur le programme C Fonction Pile d'appel, point de séquence (séquencement)

void sum(int a,int b){ 
    printf("a=%d b=%d\n",a,b); 
} 
int main(){ 
    int i=1; 
    sum(i=5,++i); 
    printf("i=%d\n\n",i); 
    /***********************/ 
    i=2; 
    sum(i=5,i++); 
    printf("i=%d\n\n",i); 
    /**********************/ 
    i=3; 
    sum(i=5,i); 
    printf("i=%d\n\n",i); 
    return 0; 
} 

Sortie:

a=5 b=5 
i=5 

a=5 b=2 
i=5 

a=5 b=5 
i=5 

Je pense que la réponse à cette question est liée au point de séquence et le point de séquence est liée à ++ opérateur ici. GCC doit suivre un ordre pour passer la valeur à empiler dans un ordre fixe mais à cause de ++ les réponses sont différentes. Je pense que pour un débutant d'écrire un appel de fonction comme celui-ci n'est pas très commun, mais la leçon sur les opérateurs est générale afin que l'on peut essayer.

Mes questions sont, quelle devrait être la réponse exacte et des questions comme celle-ci? Au cours de quelle phase de compilation ces choses sont-elles décidées (claires ou non claires)? Quel algorithme (s) particulier (soit pour l'optimisation ou en général) est impliqué? Est-ce que le même compilateur peut fournir un résultat différent pour une telle expression ou des déclarations? Et le dernier est, comment un débutant va comprendre et comprendre ces problèmes? C'est parfois très surprenant.

+0

Copie possible de [Pourquoi ces constructions (utilisant ++) undefined behavior?] (Http://stackoverflow.com/questions/949433/why-are-these-constructs-using-undefined-behavior) – Olaf

+1

La virgule dans 'sum (i = 5, ++ i);' n'est pas un point de séquence, il sépare les arguments de la fonction. La leçon est, si vous voulez utiliser différentes valeurs dérivées d'une seule variable, utilisez par exemple 'sum (i + 5, i + 1)' et mettez à jour 'i' par la suite. Ou dans ce cas, simplement 'sum (5, i + 1)'. En dehors de toute autre chose, on ne sait pas ce que vous entendez par la valeur finale de «je». Était-ce «5» ou «6» ou «2»? –

+0

oui c'est la meilleure façon d'écrire. – skyconfusion

Répondre

1

L'ordre des opérations est décidé au cours de plusieurs phases de compilation, ce qui provoque les résultats impairs que vous voyez. Au cours de la phase d'optimisation en particulier, le compilateur peut réorganiser le code d'une manière qui n'est pas toujours évidente, et dans ce cas il affecte le résultat (ce qui est bien, parce que vous faites quelque chose de non défini et que le compilateur avec ce code). Il n'y a pas d'algorithme spécifique impliqué, c'est une interaction entre plusieurs algorithmes différents appliqués à différents points et l'algorithme appliqué à chaque point peut varier en fonction de ce que le compilateur a décidé est le meilleur moyen de gérer un morceau particulier de code. Lorsque la documentation parle d'un comportement indéfini, ce n'est pas le comportement d'un compilateur spécifique qui est indéfini mais la spécification de ce que le compilateur doit ou est autorisé à faire. Le comportement du compilateur est complètement défini, mais il est défini par des décisions détaillées enfouies dans la conception de son analyseur, de son générateur de code et de ses modules optimiseurs. Il est assez compliqué pour que même les développeurs qui ont écrit le compilateur beaucoup de temps à analyser comment un bit de code donné traverse tout le processus.

Un débutant ne sera pas en mesure de comprendre le résultat. Même un développeur expert peut ne pas être capable de. C'est pourquoi «indéfini» est un mot si indésirable pour les développeurs, et pourquoi ils essaient d'éviter un comportement indéfini comme la peste. Pour citer une discussion de la spécification de langue en question, "In short, you can't use sizeof() on a structure whose elements haven't been defined, and if you do, demons may fly out of your nose.".

+0

"Le comportement du compilateur est complètement défini" - Ce n'est pas obligatoire d'être vrai. Le compilateur peut très bien utiliser des heuristiques avec un composant aléatoire. Et le lien (au moins son texte) implique quelque chose de complètement différent. Si la taille d'une 'struct' n'est pas connue, il est simplement impossible de calculer sa taille. – Olaf

+0

Il est impossible de calculer, mais parce que le résultat d'essayer de faire son comportement indéfini le compilateur est libre de lancer une erreur en supposant une taille arbitraire et en l'utilisant pour écraser la machine ou pire.Lancer une erreur parce que le calcul est impossible est simplement le comportement le plus commun (parce que la plupart des développeurs de compilateurs sont sensés et ne se mettent pas en quatre pour écrire un comportement malveillant même s'ils sont autorisés à le faire). –