c parameters de fonction ordre d’évaluation

Je comprends qu’il n’y a aucune garantie quant à l’ordre dans lequel les parameters d’une fonction seront appelés, mais n’est-il pas garanti que s’il existe un appel de fonction en tant que paramètre, cette fonction sera appelée en premier?

J’aide les étudiants dans le laboratoire d’introduction à la programmation et ils étaient supposés créer une fonction factorielle récursive qui reçoit le n (pour n!) Et un pointeur sur un entier qui sera utilisé pour compter les appels de fonctions censé imprimer les résultats (n, n! et compter).

Beaucoup se plaignaient du fait que leur utilisation des pointeurs était fausse, alors j’ai regardé le code et ils étaient tous comme ceci:

int fat(int n,int *count) { (*count)++; if(n>1) { return n * fat(n-1,count); } return 1; } int main() { int n, count=0; do { printf("Write n for fat (n >= 0): "); scanf("%d", &n); }while(n<0); printf("Input: %d. Output: %d.\nFunction called %d times.\n\n", n, fat(n, &count), count); printf("%d times\n",count); return 0; } 

En compilant avec gcc (Debian 4.7.2-5) 4.7.2, le résultat est:

 Write n for fat (n >= 0): 4 Input: 4. Output: 24. Function called 0 times. 4 times 

Donc, si fat devait être exécuté en premier, la “Fonction appelée …” devrait afficher “Fonction appelée 4 fois” au lieu de 0.

Donc, ma question est:

Même s’il est garanti qu’un appel de fonction dans un paramètre sera exécuté avant celui “recevant”, il n’est toujours pas sûr qu’il soit exécuté avant d’examiner les parameters qui ne sont pas des appels de fonction?

Une autre chose étrange est que ce même code affiche “Fonction appelée 4 fois” sur xcode …

N’est-il pas garanti que s’il y a un appel de fonction en paramètre, cette fonction sera appelée en premier?

Non, ce n’est pas garanti. L’ordre d’évaluation des parameters réels n’est pas défini. Le fait qu’un de vos parameters soit le résultat de l’évaluation d’un appel de fonction ne change rien. Les autres parameters peuvent être évalués avant l’appel de la fonction.

Avec votre exemple:

 printf("Input: %d. Output: %d.\nFunction called %d times.\n\n", n, fat(n, &count), count); 

l’appel à printf est passé 4 parameters. Ces parameters peuvent être évalués dans l’ordre choisi par le compilateur.

N’est-il pas garanti que s’il y a un appel de fonction en paramètre, cette fonction sera appelée en premier?

Il est garanti que dans un appel tel que:

 f(g(), h) 

g sera appelé avant que f soit appelé. Cependant, rien ne garantit que g est appelé avant que h soit évalué.

Généralement, si vous vous souciez de ce qui se passe en premier, mettez-les dans des déclarations séparées. De cette façon, vous ne devrez pas mémoriser les relations séquencées avant les relations ni vous demander quand des effets secondaires se produisent.

Dans votre code, printf a 4 parameters. Chacun de ces parameters doit être évalué avant d’entrer dans printf, mais l’ordre dans lequel ils sont évalués n’est pas spécifié. Les compilateurs en profitent pour optimiser le code.

C99 §6.5.2.2p10:

L’ordre d’évaluation du désignateur de fonction, des arguments réels et des sous-expressions dans les arguments réels n’est pas spécifié, mais il existe un sharepoint séquence avant l’appel réel.

 printf("Input: %d. Output: %d.\nFunction called %d times.\n\n", n, fat(n, &count), count); 

Dans ce code, il est garanti d’appeler fat() avant d’appeler printf (), mais il n’ya aucune garantie quant à l’ordre dans lequel n , fat() et count sont évalués – la valeur de count en tant qu’argument de printf() pourrait être la valeur qu’il avait avant l’appel de fat() , ou la valeur qu’il a après. De plus, je pense qu’il s’agit d’un comportement totalement indéfini, auquel cas le count pourrait également revêtir toute autre valeur.

Non, il n’y a pas de telle garantie ni en C ni en C ++ (l’exception est C #). Ainsi, les arguments d’un appel de fonction peuvent être évalués de droite à gauche (généralement pour la plupart des compilateurs) ou de gauche à droite. L’ordre d’évaluation des arguments de la fonction n’est pas spécifié.

Il est évident que vous utilisez le compilateur évalue les arguments de droite à gauche. count est mis à jour en premier et sa valeur est 0. Le compilateur évalue ensuite l’appel de la fonction fat et évalue enfin n.

Pour obtenir le résultat correct, vous devez scinder l’instruction printf en deux instructions.

 int rez = fat(n, &count); printf("Input: %d. Output: %d.\nFunction called %d times.\n\n", n, rez, count);