Uruchomiłem następujący program na moim komputerze (64-bitowy Intel z systemem Linux).
#include <stdio.h>
void test(int argc, char **argv) {\i0}
printf("[test] Argc Pointer: %p\n", &argc);
printf("[test] Argv Pointer: %p\n", &argv);
}
Int main(int argc, char **argv) {\i0}
Printf("Argc Pointer: %p\n", &argc);
printf("Argv Pointer: %p\n", &argv);
printf("Size of &argc: %lu\n", rozmiar (&argc)); printf("Rozmiar &argc: %lu\n", &argc);
printf("Size of &argv: %lu\n", size of (&argv)); printf("Size of &argv: %lu\n", size of (&argv));
test(argc, argv));
powrót 0;
}
Wyjściem programu było
$ gcc rozmiar.c -o rozmiar
$ ./rozmiar
Argc Pointer: 0x7fffd7000e4c
Argv Pointer: 0x7fffd7000e40
Wielkość &argc: 8
Rozmiar &argv: 8
[test] Argc Pointer: 0x7fffd7000e2c
Argv Pointer: 0x7fffd7000e20
Rozmiar wskaźnika &argv
wynosi 8 bajtów. Spodziewałem się, że adres argc
będzie adresem (argv) + rozmiar (argv) = 0x7ffed1a4c9f0 + 0x8 = 0x7ffed1a4c9f8
, ale pomiędzy nimi znajduje się 4-bajtowe wypełnienie. Dlaczego tak jest?
Zgaduję, że może to być spowodowane wyrównaniem pamięci, ale nie jestem pewien.
Zauważam to samo zachowanie przy funkcjach, które wywołuję.
W twoim systemie kilka pierwszych argumentów w postaci liczb całkowitych lub wskaźników jest przekazywanych w rejestrach i nie ma adresów. Gdy weźmiesz ich adresy z &argc
lub &argv
, kompilator musi sfabrykować adresy, wpisując zawartość rejestru do stosu lokalizacji i podając adresy tych stosów. Czyniąc to, kompilator wybiera, w pewnym sensie, cokolwiek się stanie z lokalizacjami stosu, które są dla niego wygodne.
Dlaczego adresy argc i argv są od siebie oddalone o 12 bajtów?
Z punktu widzenia standardu językowego, odpowiedź brzmi "brak konkretnego powodu". C nie określa ani nie implikuje żadnej zależności pomiędzy adresami parametrów funkcji. @EricPostpischil opisuje, co prawdopodobnie dzieje się w Twojej konkretnej implementacji, ale te szczegóły byłyby inne dla implementacji, w której wszystkie argumenty są przekazywane na stosie, a to nie jest jedyna alternatywa.
Co więcej, mam problem z wymyśleniem sposobu, w jaki takie informacje mogłyby być użyteczne w programie. Na przykład, nawet jeśli "wiesz", że adres argv
jest 12 bajtów przed adresem argc
, to nadal nie ma zdefiniowanego sposobu na obliczenie jednej z tych wskazówek od drugiej.