Ich habe folgendes Programm. Ich frage mich, warum es -4 auf der folgenden 64-Bit-Maschine ausgibt? Welche meiner Annahmen ist falsch gelaufen?
[Linux ubuntu 3.2.0-23-generische # 36-Ubuntu SMP Di Apr 10 20:39:51 UTC 2012 x86_64 x86_64 x86_64 GNU / Linux]
Im obigen Computer und GCC-Compiler sollte standardmäßig b zuerst und eine Sekunde gedrückt werden. Der Stapel wächst nach unten. Also sollte b eine höhere Adresse und eine niedrigere Adresse haben. Das Ergebnis sollte positiv sein. Aber ich habe -4. Kann jemand das erklären?
Die Argumente sind zwei Zeichen, die 2 Byte im Stapelrahmen belegen. Aber ich sah den Unterschied als 4, wo ich erwarte 1. Selbst wenn jemand sagt, dass es wegen der Ausrichtung ist, dann frage ich mich, ob eine Struktur mit 2 Zeichen nicht mit 4 Bytes ausgerichtet ist.
%Vor%
Der beste Weg, diese Fragen zu beantworten (über das Verhalten eines bestimmten Compilers auf einer bestimmten Plattform), ist der Assembler. Sie können gcc
erhalten, um seinen Assembler zu entladen, indem Sie das -S
-Flag übergeben (und das -fverbose-asm
-Flag ist auch nett). Ausführen
gibt ein file.s
, das ein wenig aussieht (Ich habe alle irrelevanten Bits entfernt, und die Bits in Klammern sind meine Notizen):
( Diese Frage erklärt nett, was [re]bp
und [re]sp
sind.)
Der Grund für den Unterschied ist, dass der Stack nach unten wächst: Wenn Sie also zwei Dinge auf den Stack schieben, hat der erste Push eine größere Adresse und a
wird vor b
geschoben.
Der Grund dafür ist -4
und nicht -1
. Der Compiler hat entschieden, dass das Ausrichten der Argumente auf 4 Byte Grenzen "besser" ist, wahrscheinlich weil eine 32 Bit / 64 Bit CPU mit 4 Byte besser ist Es behandelt einzelne Bytes.
(Wenn man sich den Assembler anschaut, sieht man auch den Effekt, den -mpreferred-stack-boundary
hat: es bedeutet im Wesentlichen, dass Speicher auf dem Stack in Blöcken unterschiedlicher Größe zugewiesen wird.)
Hier ist meine Vermutung:
Unter Linux in x64 gibt die Aufrufkonvention an, dass die ersten paar Parameter von register übergeben werden.
In diesem Fall werden sowohl a
als auch b
vom Register und nicht vom Stack übergeben. Da Sie jedoch seine Adresse verwenden, speichert der Compiler sie irgendwo auf dem Stapel , nachdem die Funktion aufgerufen wurde.
(In absteigender Reihenfolge nicht erforderlich.)
Es ist auch möglich, dass die Funktion einfach direkt inline ist.
In beiden Fällen erstellt der Compiler temporären Stapelspeicher zum Speichern der Variablen. Diese können in beliebiger Reihenfolge vorliegen und unterliegen Optimierungen. Sie können also nicht in einer bestimmten Reihenfolge sein, die Sie erwarten könnten.