2012-02-12 21 views
7

Od http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/Jak są dostępne zmienne lokalne funkcji ze stosu?

Oto sekwencja kroków, które ma miejsce, gdy funkcja jest nazywa:

  1. Adres instrukcji poza wywołaniem funkcji jest umieszczana na stosie. W ten sposób CPU zapamiętuje, dokąd się udać po powrocie funkcji .
  2. Pomieszczenie jest tworzone na stosie dla typu zwrotu funkcji. To jest teraz tylko symbol zastępczy.
  3. CPU przeskakuje do kodu funkcji.
  4. Bieżący wierzchołek stosu jest trzymany w specjalnym wskaźniku zwanym ramką stosu.
  5. Wszystko dodane do stosu po tym punkcie jest uważane za "lokalne" dla funkcji.
  6. Wszystkie argumenty funkcji są umieszczane na stosie.
  7. Instrukcje dotyczące funkcji rozpoczynają się.
  8. Zmienne lokalne są przesyłane na stos, tak jak są zdefiniowane.

nie jestem pewien, jak punkt # 6 dzieła. Jeśli wszystkie argumenty funkcji są umieszczone na stosie, w jaki sposób są dostępne?

Jeśli na przykład istnieją trzy argumenty a, b i c i są umieszczane na stosie jak to z góry

| a | 
| b | 
| c | 
| | 
... 
|___| 

Teraz co się dzieje, gdy funkcja chce uzyskać dostęp c? Czy pojawiły się a i b?

+1

wydaje mi się niemożliwe, że krok 3 ma miejsce przed 6: powinno być * wewnątrz * kodu funkcji ciała o ocenie osoby dzwoniącej. Nonsens! – CapelliC

Odpowiedz

1

Nie, nie są. Wskaźnik stosu (zazwyczaj rejestr esp) wskazuje na a, esp+8h punktów na b, esp+16h punktów na c i tak dalej. Nie ma potrzeby, aby się pojawiało.

Należy zauważyć, że jest to szczegół wdrożenia. Nie powinieneś się o to martwić. Podana przeze mnie liczba jest czysto teoretyczna, na niektórych architekturach adresy zstępujące podane są do ostatnich parametrów, a inne na odwrót. Nie ma gwarancji, że tak się stanie.

EDIT: Wydaje mi się, że to nie jest wiarygodne źródło informacji. Mówi o stosach i stertach, ale są to szczegóły dotyczące implementacji i może nawet nie istnieć.

Nie ma ograniczeń w standardzie dla niczego, co można zaimplementować za pomocą stosu. Na przykład wygenerowałem następujący kod:

void foo(int x, int y, int z) 
{ 
01241380 push  ebp 
01241381 mov   ebp,esp 
01241383 sub   esp,0CCh 
01241389 push  ebx 
0124138A push  esi 
0124138B push  edi 
0124138C lea   edi,[ebp-0CCh] 
01241392 mov   ecx,33h 
01241397 mov   eax,0CCCCCCCCh 
0124139C rep stos dword ptr es:[edi] 
    int c = x; 
0124139E mov   eax,dword ptr [x] 
012413A1 mov   dword ptr [c],eax 
    c = y; 
012413A4 mov   eax,dword ptr [y] 
012413A7 mov   dword ptr [c],eax 
    c = z; 
012413AA mov   eax,dword ptr [z] 
012413AD mov   dword ptr [c],eax 
} 
012413B0 pop   edi 
012413B1 pop   esi 
012413B2 pop   ebx 
012413B3 mov   esp,ebp 
012413B5 pop   ebp 

Widzisz, nie ma tam stosu. Środowisko wykonawcze ma bezpośredni dostęp do elementów: dword ptr [x], itp.

+0

Ale generalnie stos jest zaimplementowany w taki sposób, że nie można uzyskać dostępu do elementu w inny sposób niż implementacja 'top()' .. czego brakuje? – Lazer

+1

@Lazer: Nie. Stack to struktura danych, w której możesz dodawać i usuwać elementy z góry stosu w stałym czasie. Nikt nie powiedział, że nie możesz uzyskać dostępu losowego. – ybungalobill

0

Używa wskaźnika stosu i adresu względnego do wskazania c.

11

Stos jest zestawem metaforycznym . Pamiętaj, że to nadal RAM, dzięki czemu możesz uzyskać dostęp do każdego adresu, nie odpychając się, jeśli wiesz, czego szukasz.

Od rozmiarze automatyczną zmiennej jest znany w czasie kompilacji - ślady kompilatora offset dla każdej zmiennej, offset określa skąd sekcja zmienne automatyczne na stosie start [lub głowa stosie, zarówno są ważne i konkretne implementacja zależy od architektury] i ma do nich dostęp tylko przez: start + offset dla każdego przesunięcia zmiennej.

+0

Na każdej platformie, z którą możesz się spotkać, jest to metaforyczny stos. Jeśli był to prawdziwy stos, który miał tylko operacje push i pop, to funkcja musiałaby wyłączyć parametry, gdyby potrzebowała ich "niesprawności". –

+0

gdzie w pamięci są przechowywane przesunięcia? –

+0

@CaisManai Przesunięcie jest znane w czasie kompilacji i nie musi być przechowywane w pamięci. – amit

Powiązane problemy