Ces longs raccourcis
Certains raccourcis peuvent parfois ralonger certaines routes. Par example, il est souvent requis d’échanger deux variables entre elles. Pour peu que cet échange doive avoir lieu au sein d’une boucle, disons pour un affichage fluide par ex., on va chercher à en optimiser l’échange.
De manière logique, on pense de suite à utiliser une variable intermédiaire :
-
void main()
-
{
-
int a = 0;
-
int b = 1;
-
int c;
-
-
// swap utilisant une 3e variable
-
c = a;
-
a = b;
-
b = c;
-
}
Cette méthode a beau avoir certains défauts, elle est en tout cas très clair.
Il y a pourtant plus court à écrire :
-
void main()
-
{
-
int a = 0;
-
int b = 1;
-
-
// en une ligne!
-
a+=b-=a=b-a;
-
}
Ou du moins c’est ce que l’on pourrait croire… Regardons le code assembleur généré par les deux corps de programmes précédents:
Swap à 3 variables :
-
push edi ; preparer de la place
-
push esi ; pour 3 variables
-
push ebx
-
cmp dword ptr ds:[00312E08h],0
-
je 00000011
-
call 78ACB4AF
-
xor esi,esi ; a = 0
-
xor edi,edi ; b = 0
-
xor ebx,ebx ; c = 0
-
xor esi,esi ; a = 0
-
mov edi,1 ; b = 1
-
mov ebx,esi ; c = a
-
mov esi,edi ; a = b
-
mov edi,ebx ; b = c
Swap en une ligne :
-
push edi ; preparer de la place
-
push esi ; pour 2 variables
-
cmp dword ptr ds:[003F2E08h],0
-
je 00000010
-
call 7963B4AF
-
xor esi,esi ; a = 0
-
xor edi,edi ; b = 0
-
xor esi,esi ; a = 0
-
mov edi,1 ; b = 1
-
mov eax,edi ; eax = reg. temporaire
-
sub eax,esi ; eax = b - a
-
mov esi,eax ; a = b - a
-
sub edi,esi ; b = b - a
-
add esi,edi ; a = a + b
On économise peut-être du tps en n’allouant pas de place pour une troisième variable, on le paye plus tard. Au final, le swap en une seule ligne prendra légèrement plus de temps que le swap sur 3 lignes. Plus important encore, le swap en une ligne est beaucoup moins lisible… Autant donc travailler clairement!!
Remarque :
Il existe une version optimale d’un échange de deux variables, détaillée ici : http://en.wikipedia.org/wiki/XOR_swap . Certains diront que cette version n’est pas entièrement portable… Mais ca reste à prouver, je l’ai vu tourner un peu partout… La technique consiste à utiliser la commande XOR qui est plus rapide que la commande MOV, comme ceci:
-
void main()
-
{
-
int a = 0;
-
int b = 1;
-
-
// avec des Xor :
-
a = a ^ b;
-
b = a ^ b;
-
a = a ^ b;
-
}
Ce qui donne :
-
push edi
-
push esi
-
cmp dword ptr ds:[00212E08h],0
-
je 00000010
-
call 7974B4AF
-
xor esi,esi
-
xor edi,edi
-
xor esi,esi
-
mov edi,1
-
xor esi,edi
-
xor edi,esi
-
xor esi,edi
Encore une fois, la lisibilité n’est pas optimale, à moins d’être habitué à faire des XOR!