Der Grund, warum die Adresse j
ändert sich nie, weil der Compiler Speicher für j
auf dem Stapel reserviert, wenn die Funktion im Gegensatz zu betreten, wenn j
kommt in Umfang.
Wie immer kann es hilfreich sein, wenn Sie sich den Assembler-Code anschauen. Nehmen Sie die folgende Funktion: -
int foo(void)
{
int i=3;
i++;
{
int j=2;
i=j;
}
return i;
}
gcc wandelt diese in der folgenden x86-Assembler-Code: -
foo:
pushl %ebp ; save stack base pointer
movl %esp, %ebp ; set base pointer to old top of stack
subl $8, %esp ; allocate memory for local variables
movl $3, -4(%ebp) ; initialize i
leal -4(%ebp), %eax ; move address of i into eax
incl (%eax) ; increment i by 1
movl $2, -8(%ebp) ; initialize j
movl -8(%ebp), %eax ; move j into accumulator
movl %eax, -4(%ebp) ; set i to j
movl -4(%ebp), %eax ; set the value of i as the function return value
leave ; restore stack pointers
ret ; return to caller
Lasst uns dieses Assembler-Code zu Fuß durch. Die erste Zeile speichert den aktuellen Stapel-Basiszeiger, so dass er wiederhergestellt werden kann, wenn die Funktion beendet wird, die zweite Zeile legt den aktuellen Anfang des Stapels als neuen Stapel-Basiszeiger für diese Funktion fest.
Die dritte Zeile ist diejenige, die den Speicher auf dem Stapel für alle lokalen Variablen reserviert. Der Befehl subl $8, %esp
subtrahiert 8 vom aktuellen Anfang des Stapelzeigers, dem esp
Register. Stapel werden im Speicher größer, sodass diese Codezeile den Speicher im Stapel um 8 Byte erhöht. Wir haben zwei Ganzzahlen in dieser Funktion, i
und j
, von denen jede 4 Bytes benötigt, weshalb sie 8 Bytes zuweist.
Zeile 4 initialisiert i
zu 3, indem direkt in eine Adresse auf dem Stapel geschrieben wird. Die Zeilen 5 und 6 laden und inkrementieren dann i
. Zeile 7 initialisiert j
, indem der Wert 2 in den Speicher geschrieben wird, der für j
auf dem Stapel reserviert ist. Beachten Sie, dass, wenn in Zeile 7 in den Geltungsbereich kam, der Assembly-Code den Stack nicht angepasst hat, um Speicher für ihn zuzuweisen, der bereits früher erledigt wurde.
Ich bin mir sicher, dass es offensichtlich ist, aber der Grund, warum der Compiler den Speicher für alle lokalen Variablen zu Beginn der Funktion reserviert, ist, weil es viel effizienter ist, dies zu tun. Das Anpassen des Stapels jedes Mal, wenn eine lokale Variable in den Bereich hinein oder aus ihm herausfiel, würde zu vielen unnötigen Manipulationen des Stapelzeigers führen, ohne Verstärkung.
Ich bin sicher, Sie können herausfinden, was der Rest des Assembly-Codes selbst tut, wenn Sie nicht einen Kommentar posten und ich werde Sie durchgehen.
Ich habe versehentlich die falsche Frage gepostet .. Meine schlechte .. Entschuldigung ..Ich habe die Frage –
@Gardener aktualisiert: es wird gut kompilieren. 'void *' wird automatisch umgewandelt. –
Sie haben die Frage jetzt geändert. Hast du es getestet, um zu sehen, ob deine ursprüngliche Behauptung immer noch wahr ist? Es ist nicht einmal ein gültiger Code, also ist die Antwort fast sicher nein. – Clifford