Greg's Devblog Par un développeur, pour les développeurs

27sept/104

Qu’affiche le code suivant ?

Sous ce titre un peu racoleur se cache pourtant un phénomène assez étrange, qui fait qu'en C il n'est pas toujours facile de déterminer le résultat d'une instruction...

Voici donc un petit programme rapide, de quelques lignes ; je vous invite à essayer de deviner ce qu'il affiche...

#include <stdio.h>

int main(int argc, char **argv){
	int w = 0, x = 0, y = 0, z = 0;

	printf("w : %i %i\n", w++, w);
	printf("x : %i %i\n", x++, x+1);
	printf("y : %i %i\n", y, y++);
	printf("z : %i %i\n", z+1, z++);
	return 0;
}

Ca va paraître bizarre, mais en compilant le code sous OSX avec GCC je n'ai pas obtenu le même résultat que sous Windows (pourtant toujours avec GCC, mais probablement avec des options de compilation différentes). En utilisant cygwin et en compilant en ligne de commande (sous Windows, donc), j'obtiens bien le même résultat que sous OSX et Linux... Voici donc les 2 résultats obtenus :

Avec Code::Blocks

w : 0 0
x : 0 1
y : 1 0
z : 2 0

Ici, le résultat parait dans l'ensemble cohérent, si en tient compte d'un élément bizarre : on dirait que les opérations sont effectuées de droite à gauche : si dans la partie de droite on incrémente la variable, alors dans la partie de gauche la valeur sera (valeur+1), comme en témoignent les lignes 3 et 4.

Avec GCC sans option

w : 0 1
x : 0 1
y : 1 0
z : 2 0

Autre résultat, autre constant : cette fois-ci le résultat parait moins cohérent. En effet, les lignes 1 et 2, affichent le même résultat, alors que dans un cas on affiche "w", et dans l'autre "x+1"... L'explication semblerait être qu'on effectue en premier les opérations, de droite à gauche, puis on met les valeurs. Donc pour "w++, w", on incrémente d'abord w, puis on met les valeurs dans les arugments, alors que pour "x++, x+1", on calcule en premier x+1, puis on incremente avec x++, et les 2 valeurs stockées sont utilisées pour les arguments.

Que peut-on déduire de cet exemple foireux ?

  • Savoir exactement ce que fait un code n'est pas forcément simple.
  • Les warnings ne sont pas là pour rien... En l’occurrence, en activant les warnings on obtient ici "warning: operation on `w' may be undefined"... Pourtant, pas mal de monde semble considérer que "si ça compile, c'est que c'est bon", et on se retrouve avec des programmes bourrés de warnings (et donc potentiellement de bugs dans ce genre).

D'ailleurs, j'utilise souvent Code::Blocks, qui a une manie assez bizarre : si on compile avec "build and run" et qu'il n'y a pas d'erreur, et même s'il y a des centaines de warnings, Clode::Blocks vide le log de compilation et n'affiche rien... Il faut alors recompiler (sans exécuter) pour voir apparaître les warnings (pour peu qu'on ait fait une modification rapide dans un des fichiers pour "forcer" la recompilation...).

Méfiance !

Commentaires (4) Trackbacks (0)
  1. J’imagine que ce genre de code dépend de l’ordre dans lequel les arguments se retrouvent sur la pile, puisque l’ordre d’évaluation des arguments d’une fonction n’est pas défini par le langage. Le danger du code présenté vient du fait qu’il y a un effet de bord dans une des expressions qui peut avoir un impact sur d’autres expressions de la même commande. Genre, « que fait *p++=*p++ ». Les warnings sont en effet là pour avertir le programmeur que son code comporte des risques (ou peut produire des effets différents avec d’autres compilateurs).

    On ne le répètera jamais assez: Le warning est ton ami. C’est d’autant plus important à comprendre quand on vient d’un langage comme Java où il y a finalement assez peu de warning et que le compilateur s’interrompt pour un « throw non déclaré ».

  2. En fait, ici, tu souligne la différence entre p++ et ++p :-)
    Dans l’un, on renvoi p, dans l’autre p+1, mais les deux incrémente p au final

    • Non, si tu regardes bien à chaque fois j’ai mis p++ ^^

      Mais si tu regardes le résultat avec GCC :

      printf(« w : %i %i\n », w++, w) => « 0 1″
      printf(« x : %i %i\n », x++, x+1); => « 0 1″

      Là clairement on a un souci… Car il n’y a intuitivement pas de raison pour que w et x+1 donnent le même résultat…


Laisser un commentaire


Aucun trackbacks pour l'instant