2014-04-25 25 views
6

Próbuję zrozumieć ramkę stosu w C, więc napisałem prosty kod C, aby przeanalizować ramkę stosu.Zrozumienie ramek stosu w C

  • Przede wszystkim fun1() zwraca adres zmiennej lokalnej, który jest inicjowany do 10 do ptr co prowadzi do ostrzeżenia, ale to jest ok ... Jeśli mogę wydrukować wartość * ptr teraz drukuje 10, nawet to w porządku ...

  • Następna fun2() zwraca adres zmiennej lokalnej, która nie została zainicjalizowana i jeśli spróbuję wydrukować wartość * ptr, teraz drukuje 10 bez względu na to, czy jestem zwracając adres a lub b ...

  • Aby zrozumieć, co się tutaj dzieje, skorzystałem z gdb. Korzystanie z gdb, zacząłem krok po kroku debugowania i kiedy osiągnął linię „zwrot &” w fun2(), próbowałem wydrukować adres B, drukiem & b ale drukowane nie potrafisz przyjąć adres "b", który nie jest lwartością.

nie rozumiem, gdy próbuję wydrukować adresu, druku & drukuje absolutnie w porządku, to dlaczego nie adres b. * Dlaczego nie ma b lwartości, gdy a jest?

# include <stdio.h> 

int * fun1() { 
    int a = 10; 
    return &a; 
} 

int * fun2() 
{ 
    int a; 
    int b; 
    return &a;   // return &b; 
} 

int main() 
{ 
    int *ptr; 
    ptr = fun1(); 
    ptr = fun2(); 
    printf ("*ptr = %d, fun2() called...\n", *ptr); 
    return 0; 
} 
+0

http://stackoverflow.com/a/18479996/1814023 –

+1

pan powołując niezdefiniowanej zachowanie. Nie ma gwarancji, że wyniki będą miały jakikolwiek sens, lub zrobią to, czego można oczekiwać od układu stosu. Standardowa hiperbola polega na tym, że program może zrobić [demony] (http://www.catb.org/jargon/html/N/nasal-demons.html) wyskoczyć z nosa. – user2357112

+2

Masz szczęście, że drukowanie '* ptr' drukuje 10; na pewno nie jest to gwarantowane (przywołujesz niezdefiniowane zachowanie). Ale naprawdę powinieneś pokazać cały kod. W kodzie kompilator prawdopodobnie upuścił 'b' jako nieużywaną zmienną, więc nie ma lokalizacji, dlatego nie można wziąć jej adresu. Użyj 'b' w kodzie, w jakiś sposób, i będziesz mógł go wydrukować. I proszę, nie zgłaszaj "czegoś w stylu"; być precyzyjnym i dokładnie raportować, co mówi debugger. –

Odpowiedz

3

Kompilator optymalizuje trochę kodu w fun2.

Po odesłaniu numeru &a następuje optymalizacja z dala int b;. Jeśli zwrócisz &b, to zoptymalizujesz od siebie int a;. Jeśli dodasz obojętne obliczenia, zobaczysz, że adresy zwracanych wartości będą różne.

int * fun2() 
{ 
    int a; 
    int b; 
    int* p = &a; 
    p = &b; 
    return p; 
} 

Zmień main wydrukować zwróconych wartości fun1 i fun2.

int main() 
{ 
    int *ptr; 
    ptr = fun1(); 
    printf ("ptr = %p, fun1() called...\n", ptr); 
    ptr = fun2(); 
    printf ("ptr = %p, fun2() called...\n", ptr); 
    printf ("*ptr = %d, fun2() called...\n", *ptr); 
    return 0; 
} 

Kiedy uruchomić ten kod, otrzymuję następujący wynik próbki:

 
ptr = 0x7ffff98c70ec, fun1() called... 
ptr = 0x7ffff98c70e4, fun2() called... 
*ptr = 32749, fun2() called... 
+0

Ya that's true, jeśli zainicjalizuję b, zwraca śmieci, ale to samo powinno być prawdą, jeśli kompiluję z optymalizacją -O0. Ale kiedy skompiluję go z optymalizacją -O0, wynik jest taki sam, tj. 10 – Adarsh

0

To kompiluje dla mnie po prostu w porządku po powrocie adres do b. Ale nie powinieneś zwracać adresu zmiennej lokalnej. Check out this link.

+0

To prawda, ale moim celem nie jest osiągnięcie niczego z tego kodu, ale zrozumienie, w jaki sposób adres zmiennej stosu wykorzystywanej w jednej funkcji może być ponownie użyty w innej funkcji ... Dzięki za pomoc ... – Adarsh