69 votes

Ordre d'évaluation des paramètres avant une fonction appelant en C

Peut-on supposer un ordre d'évaluation des paramètres de la fonction lors de son appel en C? D'après le programme suivant, il semble qu'il n'y ait pas d'ordre particulier lorsque je l'ai exécuté.

 #include <stdio.h>

int main()
{
   int a[] = {1, 2, 3};
   int * pa; 

   pa = &a[0];
   printf("a[0] = %d\ta[1] = %d\ta[2] = %d\n",*(pa), *(pa++),*(++pa));
   /* Result: a[0] = 3  a[1] = 2    a[2] = 2 */

   pa = &a[0];
   printf("a[0] = %d\ta[1] = %d\ta[2] = %d\n",*(pa++),*(pa),*(++pa));
   /* Result: a[0] = 2  a[1] = 2     a[2] = 2 */

   pa = &a[0];
   printf("a[0] = %d\ta[1] = %d\ta[2] = %d\n",*(pa++),*(++pa), *(pa));
   /* a[0] = 2  a[1] = 2 a[2] = 1 */

}
 

65voto

Grant Wagner Points 14085

Non, les paramètres de fonction ne sont pas évalués dans un ordre défini en C.

Voir les réponses de Martin York à Quels sont tous les comportements non définis communs qu'un programmeur c ++ devrait connaître? .

19voto

Robert Gamble Points 41984

L'ordre d'évaluation des arguments de la fonction est indéterminée, à partir de C99 §6.5.2.2p10:

L'ordre d'évaluation de la la fonction de désignation, la réelle les arguments et les sous-expressions dans les arguments n'est pas spécifié, mais il y a un point de séquence avant l'appel réel.

Libellé similaire existe en C89.

En outre, vous modifiez pa plusieurs fois sans l'intervention de la séquence de points qui invoque un comportement indéfini (l'opérateur virgule introduit un point de séquence, mais les virgules délimitant les arguments de la fonction ne sont pas). Si vous activez les mises en garde sur votre compilateur qu'il doit vous avertir à ce sujet:

$ gcc -Wall -W -ansi -pedantic test.c -o test
test.c: In function ‘main':
test.c:9: warning: operation on ‘pa' may be undefined
test.c:9: warning: operation on ‘pa' may be undefined
test.c:13: warning: operation on ‘pa' may be undefined
test.c:13: warning: operation on ‘pa' may be undefined
test.c:17: warning: operation on ‘pa' may be undefined
test.c:17: warning: operation on ‘pa' may be undefined
test.c:20: warning: control reaches end of non-void function

14voto

Pitje Puck Points 89

Juste pour ajouter quelques expériences.
Le code suivant:

 int i=1;
printf("%d %d %d\n", i++, i++, i);
 

résulte en

2 1 3 - en utilisant g ++ 4.2.1 sur Linux.i686
1 2 3 - utilisant SunStudio C ++ 5.9 sur Linux.i686
2 1 3 - en utilisant g ++ 4.2.1 sur SunOS.x86pc
1 2 3 - en utilisant SunStudio C ++ 5.9 sur SunOS.x86pc
1 2 3 - en utilisant g ++ 4.2.1 sur SunOS.sun4u
1 2 3 - utilisation de SunStudio C ++ 5.9 sur SunOS.sun4u

6voto

abelenky Points 28063

S'il est vrai que l'ordre d'évaluation des paramètres n'est pas défini, les compilateurs que j'ai rencontrés jusqu'à présent le font tous de droite à gauche. Je ne dépendrais jamais de ce comportement, mais il est intéressant de noter.

L'exemple le plus simple que je connaisse est:

 int i=1;
printf("%d %d %d", i++, i++, i++);
 

Avec un résultat de "3 2 1"

Si quelqu'un connaît un compilateur / une plate-forme qui donne "1 2 3" ou même "3 3 3", j'aimerais connaître les détails (version du compilateur? Système d'exploitation? Matériel? Etc.).

5voto

Comme d'autres l'a déjà dit, l'ordre dans lequel les arguments de la fonction sont évalués n'est pas spécifié, et il n'y a pas de point de séquence entre les évaluer. Parce que vous changez pa par la suite en passant chaque argument, vous ne changez et ne lisez pa deux fois entre deux séquence de points. C'est en fait un comportement indéfini. J'ai trouvé une très belle explication dans le manuel de GCC, qui, je pense, pourrait être utile:

Le C et le C++ normes définit l'ordre dans lequel les expressions dans un programme C/C++ sont évaluées en fonction de la séquence de points, qui représentent un partiel de la commande entre l'exécution de certaines parties du programme: nombre de personnes exécutées avant la séquence de point, et ceux qui sont exécutés d'après elle. Ceux-ci se produisent après l'évaluation d'une expression complète (qui n'est pas partie d'une expression plus grande), et après l'évaluation du premier opérande de l'un &&, ||, ? : ou , (virgule) de l'opérateur, avant qu'une fonction est appelée (mais après l'évaluation de son argumentation et l'expression désignant la fonction appelée), et dans certains autres endroits. Autres que ce qui est exprimé par la séquence de point de règles, l'ordre d'évaluation des sous-expressions d'une expression n'est pas spécifié. Toutes ces règles décrivent seulement un ordre partiel plutôt qu'un total de la commande, puisque, par exemple, si les deux fonctions sont appelées dans une expression sans point de séquence entre eux, l'ordre dans lequel les fonctions sont appelées n'est pas spécifié. Toutefois, le comité de normalisation ont statué que les appels de fonction ne se chevauchent pas.

Il n'est pas spécifié lors de la entre la séquence des points de modifications apportées aux valeurs des objets prennent effet. Les programmes dont le comportement dépend de cette avoir un comportement indéfini; le C et le C++ normes précisent que "Entre le précédent et suivant de la séquence de point d'un objet doit avoir sa valeur stockée modifié plus d'une fois par l'évaluation d'une expression. En outre, l'état de la valeur est en lecture seule pour déterminer la valeur à stocker.". Si un programme ne respecte pas ces règles, les résultats sur n'importe quel particulier de mise en œuvre sont tout à fait imprévisible.

Des exemples de code avec un comportement indéfini sont a = a++;, a[n] = b[n++] et a[i++] = i;. Certains des cas les plus complexes ne sont pas diagnostiqués par cette option, et il peut donner occasionnellement un résultat faux positif, mais en général, il a été trouvé assez efficace pour détecter ce genre de problème dans les programmes.

La norme est rédigée de prêter à confusion, donc il y a un débat sur le sens précis de la séquence de point de règles en cas subtils. Des liens vers des discussions du problème, y compris des propositions de définitions formelles, peut être trouvé sur la GCC lectures de la page, à http://gcc.gnu.org/readings.html.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X