Ich habe das folgende Programm auf meinem Computer ausgeführt (64-Bit-Intel mit Linux).
#include <stdio.h>
void test(int argc, char **argv) {
printf("[test] Argc Pointer: %p\n", &argc);
printf("[test] Argv Pointer: %p\n", &argv);
}
int main(int argc, char **argv) {
printf("Argc Pointer: %p\n", &argc);
printf("Argv Pointer: %p\n", &argv);
printf("Size of &argc: %lu\n", sizeof (&argc));
printf("Size of &argv: %lu\n", sizeof (&argv));
test(argc, argv);
return 0;
}
Die Ausgabe des Programms war
$ gcc size.c -o size
$ ./size
Argc Pointer: 0x7fffd7000e4c
Argv Pointer: 0x7fffd7000e40
Size of &argc: 8
Size of &argv: 8
[test] Argc Pointer: 0x7fffd7000e2c
[test] Argv Pointer: 0x7fffd7000e20
Die Größe des Zeigers &argv
ist 8 Byte. Ich erwartete die Adresse von argc
sein address of (argv) + sizeof (argv) = 0x7ffed1a4c9f0 + 0x8 = 0x7ffed1a4c9f8
Dazwischen befindet sich jedoch ein 4-Byte-Padding. Warum ist das so?
Meine Vermutung ist, dass es an der Speicherausrichtung liegen könnte, aber ich bin mir nicht sicher.
Ich bemerke das gleiche Verhalten bei den Funktionen, die ich auch aufrufe.
Auf Ihrem System werden die ersten Ganzzahl- oder Zeigerargumente in Registern übergeben und haben keine Adressen. Wenn Sie ihre Adressen mitnehmen &argc
oder &argv
, muss der Compiler Adressen fabrizieren, indem er die Registerinhalte in Stapelspeicherplätze schreibt und Ihnen die Adressen dieser Stapelspeicherplätze gibt. Dabei wählt der Compiler gewissermaßen die Stack-Positionen aus, die ihm gerade am besten passen.
Warum liegen die Adressen von argc und argv 12 Bytes auseinander?
Aus Sicht des Sprachstandards lautet die Antwort „kein besonderer Grund“. C spezifiziert oder impliziert keine Beziehung zwischen den Adressen von Funktionsparametern. @EricPostpischil beschreibt, was wahrscheinlich in Ihrer speziellen Implementierung passiert, aber diese Details wären bei einer Implementierung anders, bei der alle Argumente an den Stapel übergeben werden, und das ist nicht die einzige Alternative.
Außerdem fällt es mir schwer, einen Weg zu finden, wie solche Informationen in einem Programm nützlich sein könnten. Zum Beispiel, auch wenn Sie “wissen”, dass die Adresse von argv
ist 12 Bytes vor der Adresse von argc
gibt es immer noch keine definierte Möglichkeit, einen dieser Zeiger aus dem anderen zu berechnen.
Warum nicht? Sie könnten 174 Bytes voneinander entfernt sein. Eine Antwort hängt von Ihrem Betriebssystem und/oder einer Wrapper-Bibliothek ab, die eingerichtet wird
main
.– Aschepler
8. Februar 2020 um 15:38 Uhr
@aschepler: Es sollte nicht von einem Wrapper abhängen, der eingerichtet wird
main
. In C,main
kann als reguläre Funktion aufgerufen werden, muss also wie eine reguläre Funktion Argumente empfangen und der ABI gehorchen.– Eric Postpischil
8. Februar 2020 um 15:52 Uhr
@aschelper: Ich bemerke das gleiche Verhalten auch für andere Funktionen.
– letmutx
8. Februar 2020 um 15:55 Uhr
Es ist ein interessantes „Gedankenexperiment“, aber eigentlich gibt es nichts, was mehr sein sollte als ein „Ich frage mich, warum“. Diese Adressen können sich je nach Betriebssystem, Compiler, Compilerversion, Prozessorarchitektur ändern und sollten in keiner Weise im „echten Leben“ verwendet werden.
– Neil
9. Februar 2020 um 12:31 Uhr
das Ergebnis von sizeof muss mit gedruckt werden
%zu
– phuklv
10. Februar 2020 um 3:22 Uhr