Il est vrai qu'une expression tableaux ( tab[i] ) est remplacée par celle -ci ( *(ptr+i) ) lors de la compilation (je ne suis pas expert) mais pensez-vous (@Bktero) que le compilateur transforme le code ou il applique juste une arithmétique de pointeur ?. En clair manipule t'il juste l'adresse du tableau pour accéder aux éléments de celui-ci (en ajoutant la taille en octet du type de l'élément du tableau ou pointe sur le tableau afin de la manipuler voire autre ).Vos réponses m'éclairement surement
Je ne sais pas trop quoi te répondre...
Je sais pas si on peut dire qu'une expression est "remplacée" par une autre. Elles sont simplement la même signification, la même valeur. Qu'est ce que cela veut dire "le compilateur transforme le code" ? Qu'il remplace un morceau de code source par un autre avant de compiler ? Il n'a pas besoin de faire ça, il compile ligne par ligne sans remplacer quoi que ce soit : ce n'est de toute façon pas nécessaire de remplacer puisqu'il est en train de l'interpréter et s'il sait ce que ça veut dire, pourquoi remplacer par autre chose pour interpréter ensuite cette autre chose ?
En gros, tab[i] est équivalent à *(tab + i) (ton code peut écrire soit l'un soit l'autre) et le compilateur remplace tab l'adresse de l'objet en mémoire. Si au lieu de tab, tu avais ptr (un pointeur) alors le compilateur le remplacerait par la valeur de la variable.
J'ai essayé de regarder un peu d'assembleur pour comprendre. Voici le code source :
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <stdlib.h>
int f(void)
{
int array[10];
return array[5];
}
int g(void)
{
int *pointer = malloc(10);
return pointer[5];
} |
Je compile et je dump l'assembleur (ARM) :
$ arm-none-eabi-gcc -O1 main.c -c && arm-none-eabi-objdump -d -l main.o
main.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <f>:
f():
0: e24dd028 sub sp, sp, #40 ; 0x28
4: e59d0014 ldr r0, [sp, #20]
8: e28dd028 add sp, sp, #40 ; 0x28
c: e12fff1e bx lr
00000010 <g>:
g():
10: e92d4008 push {r3, lr}
14: e3a0000a mov r0, #10
18: ebfffffe bl 0 <malloc>
1c: e5900014 ldr r0, [r0, #20]
20: e8bd4008 pop {r3, lr}
24: e12fff1e bx lr
Ce sont les lignes 4 et 1c qui sont intéressantes pour comparer pointeurs et tableaux. Notez que r0 est le registre dédié pour les valeurs de retour ainsi qu'au premier paramètre de fonctions.
- Pour f() (ligne 4), on met dans r0 la valeur trouvée à sp + 20 (sp = stack pointer). Le tableau est bien déclaré sur la pile (ligne 0) et le 5e élément est 20 octets (5 * sizeof int = 5 * 4 = 20). On décrémente ensuite sp pour détruire le tableau crée sur la pile.
- Pour g(), malloc() met l'adresse de la zone allouée dans r0 (ligne 18). Le retour de g() est donc la valeur trouvée à l'adresse contenu dans r0 augmentée de 20 octets.
Pour les 2 fonctions, l'appelant trouvera la valeur voulue dans r0 une fois f() et g() terminée.
Partager