En C, l'ordre de calcul des arguments d'une fonction n'est pas défini par la norme (jusqu'à C99 inclus). Les arguments peuvent être calculés de gauche à droite, de droite à gauche ou dans tout autre ordre (à la discrétion du compilateur ou de l'architecture).
void fn(int a, int b) { /* ... */ } int x = 1; fn(x++, x++); // l'ordre de calcul de x++ et x++ n'est pas défini !
"Dans quel ordre les arguments d'une fonction sont-ils calculés en C et peut-on s'y fier lors de l'écriture du code ?"
Une erreur fréquente est de penser que les arguments sont calculés de gauche à droite (par analogie avec les expressions). En pratique, chaque appel de fonction est compilé à la discrétion du compilateur (et de la plateforme).
void foo(int a, int b, int c); int x = 1; foo(x++, x++, x++); // le résultat dépend de l'ordre de calcul des arguments
Véritable réponse : on ne peut pas s'y fier — le comportement n'est pas défini !
Histoire
Dans un produit multiplateforme, un programmeur a écrit
push(stack, stack->size++, data);. Sur la plupart des plateformes, tout fonctionnait, mais sur une, la taille de la pile augmentait avant la transmission des données, tandis que sur une autre, après. Les données "se perdaient" ou étaient adressées incorrectement, l'erreur se manifestait rarement et était très difficile à déboguer.
Histoire
Dans une bibliothèque de protocole réseau, la fonction de journalisation était appelée avec des expressions-arguments incrémentant des compteurs statistiques. Les rapports statistiques étaient générés de manière incorrecte : pour différents clients, les indices des compteurs différaient, car ils n'étaient pas exécutés dans l'ordre prévu.
Histoire
Dans une interface de gestion de matériel, la fonction d'initialisation passait des pointeurs et des décalages avec incrément à l'intérieur des arguments (du type
init(ptr++, cnt++);). Sur certains processeurs, le matériel s'initialisait correctement, tandis que sur d'autres, un échec survenait, la cause étant longtemps recherchée dans le matériel, alors que le problème se situait dans un code C incorrect.