2015-02-17 20 views
6

Próbuję zrozumieć, w jaki sposób C przydziela pamięć na stosie. Zawsze uważałem, że zmienne na stosie mogą być przedstawiane jak zmienne składowe struktury, zajmują kolejne, ciągłe bloki bajtów wewnątrz stosu. Aby pomóc zilustrować ten problem, znalazłem gdzieś, stworzyłem ten mały program, który powielał to zjawisko.Czy zmienne stosu C są przechowywane w odwrotnej kolejności?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

void function(int *i) { 
    int *_prev_int = (int *) ((long unsigned int) i - sizeof(int)) ; 
    printf("%d\n", *_prev_int);  
} 

void main(void) 
{ 
    int x = 152; 
    int y = 234; 
    function(&y); 
} 

Zobacz co robię? Załóżmy, że sizeof(int) jest 4: szukam 4 bajtów za przekazanym wskaźnikiem, ponieważ odczytałoby to 4 bajty przed miejscem, w którym int y w stosie dzwoniącego .

Nie wydrukować 152. Co dziwne, kiedy patrzę na najbliższe 4 bajty:

int *_prev_int = (int *) ((long unsigned int) i + sizeof(int)) ; 

i teraz działa drukuje cokolwiek w x wewnątrz stosu rozmówcy. Dlaczego x ma niższy adres niż y? Czy zmienne stosu są przechowywane do góry nogami?

+0

stos jest przechowywany w dół – Ajit

+2

Myślę, że jest to implementacja zdefiniowana/lub nieokreślona. Sprawdź tę odpowiedź http://stackoverflow.com/a/4105123/1673391 –

+3

Jest to całkowicie zależne od platformy, ale wiele popularnych platform faktycznie zwiększa wysokość stosu z sekcji kodu/danych i stos w dół od góry (dostępny) pamięć. Powinieneś ** nigdy ** polegać na tym w twoim kodzie C, chociaż ... – DevSolar

Odpowiedz

10

Organizacja stosu jest całkowicie nieokreślona i jest to implementacja specyficzna. W praktyce zależy to od dużej ilości kompilatora (nawet od jego wersji) i flag optymalizacyjnych.

Niektóre zmienne nie mieszczą się nawet na stosie (np. Dlatego, że po prostu są przechowywane w niektórych rejestrach lub ponieważ kompilator je zoptymalizował - np. Przez wstawianie, stałe składanie itp.).

BTW, możesz mieć hipotetyczną implementację C, która nie używa żadnego stosu (nawet jeśli nie mogę nazwać takiej implementacji).

Aby zrozumieć więcej o stosach:

  • Przeczytaj wikipage na call stacks, tail calls, threads, a na continuations

  • Zapoznanie się z Twoim komputerem, architecture & instruction set (np x86) & ABI, następnie ...

  • poprosić kompilator, aby pokazać kod asemblera i/lub pośrednie reprezentacje kompilatora. Jeśli używasz GCC, skompiluj prosty kod z gcc -S -fverbose-asm (aby uzyskać kod assemblera foo.s podczas kompilowania foo.c) i wypróbuj kilka poziomów optymalizacji (co najmniej -O0, -O1, -O2 ....). Wypróbuj także opcję -fdump-tree-all (zrzuca setki plików pokazujących wewnętrzne reprezentacje kompilatora dla twojego kodu źródłowego). Zauważ, że GCC zapewnia również starego papieru return address builtins

  • Przeczytaj Appel w sprawie garbage collection can be faster than stack allocation i zrozumieć garbage collection technik (ponieważ często trzeba sprawdzić i ewentualnie zmienić niektóre wskaźniki wewnątrz ramki stosu wywołań). Aby dowiedzieć się więcej o GC, przeczytaj GC handbook.

Niestety, nie znam języka niskiego poziomu (takich jak C, D, rdza, C++, idź, ...), gdzie stos wywołań jest dostępny na poziomie języka.To dlatego kodowanie odśmiecacza dla C jest trudne (ponieważ GC-s muszą skanować wskaźniki stosu wywołań) ... Ale zobacz Boehm's conservative GC dla bardzo praktycznego i pragmatycznego rozwiązania.

+0

należy podać standard dla takich twierdzeń/komentarzy –

+4

AFAIK, standard C99 nie wspomina o żadnym stosie w normatywny sposób. –

+1

@GrijeshChauhan: Nie, nie wymaga cytatów ze standardu, ponieważ jest ** nieokreślony ** według normy. Dlatego nie powinieneś polegać na jego zachowaniu. – DevSolar

3

Prawie wszystkie architektury procesorów obsługują obecnie instrukcje manipulacji stosami (np. Instrukcje LDM, STM w ARM). Kompilatory za pomocą tego stosu narzędzi. W większości przypadków, gdy dane są przesyłane do stosu, wskaźnik stosu zmniejsza się (wzrasta w dół) i zwiększa się, gdy dane pojawią się ze stosu.

Zależy więc od architektury procesora i kompilatora, w jaki sposób wdrażany jest stos.

Powiązane problemy