2011-09-21 34 views
8

Theo Wiki:nhầm lẫn về chức năng gọi stack

người gọi đẩy địa chỉ trở lại vào stack, và gọi chương trình con, khi nó kết thúc, bật các địa chỉ trả lại tắt cuộc gọi ngăn xếp và chuyển quyền kiểm soát đến địa chỉ đó.

Pic từ Wiki:

enter image description here

Tôi hoàn toàn không hiểu được điều này. Nói rằng tôi có một chương trình C như sau:

#include <stdio.h> 

int foo(int x) 
{ 
    return x+1; 
} 

void spam() 
{ 
    int a = 1; //local variable 
    int b = foo(a); //subroutine called 
    int c = b; //local variable 
} 

int main() 
{ 
    spam(); 
    return 0; 
} 

Và tôi nghĩ rằng các cuộc gọi stack nên được một cái gì đó như một bản vẽ như sau:

<None> means none local variables or params 

     _| parameters for foo() <int x> |_ 
top | local of spam() <int c>  | 
^  | return address of foo()  |<---foo() called, when finishes, return here? 
|  | local of spam() <int b>  | 
bot | local of spam() <int a>  | 
     _| parameters for spam() <None> |_ 
     | locals of main() <None>  | 
     | return address of spam()  |<---spam() called, when finishes, return here? 
     | parameters for main() <None> | 

Câu hỏi:

Theo những lời trích dẫn từ Wiki,

chương trình con được gọi, khi nó kết thúc, hãy bật địa chỉ trả lại ngăn xếp cuộc gọi và chuyển quyền kiểm soát đến địa chỉ đó.

1. Bản vẽ của tôi có đúng không?

2.Nếu nó là đúng, sau đó khi foo() kết thúc, nó sẽ

pop địa chỉ trở lại ra khỏi ngăn xếp cuộc gọi và điều khiển chuyển đến giải quyết

, nhưng làm thế nào nó có thể bật ra địa chỉ trả lại không? Bởi vì khi foo kết thúc, con trỏ ngăn xếp hiện tại trỏ đến địa chỉ của thư rác, phải không?

UPDATE:

gì nếu main() trông như thế này:

int main() 
{ 
    spam(); 
    foo(); 
} 

sau đó những gì các cuộc gọi stack nên xem xét như thế nào?

Trả lời

14

Bản vẽ của bạn không chính xác. Các biến ngăn xếp cục bộ cho một hàm là tất cả bên dưới bất kỳ địa chỉ trả về nào. Nếu không, như bạn đã quan sát, người dân địa phương sẽ bị lạc khi bạn gọi một hàm.

Nó phải là như thế này:

| parameters for foo() <int x> | 
| return address of foo()  | 
| local of spam() <int c>  | 
| local of spam() <int b>  | 
| local of spam() <int a>  | 
| parameters for spam() <None> | 
| return address of spam()  | 
| locals of main() <None>  | 
| parameters for main() <None> | 

Tôi nghĩ rằng sự nhầm lẫn là bạn tin rằng khai báo biến được coi là báo cáo và thực hiện theo thứ tự. Trong thực tế, trình biên dịch thường sẽ phân tích một hàm để quyết định cần bao nhiêu không gian ngăn xếp cho tất cả các biến cục bộ. Sau đó, nó phát ra mã để điều chỉnh con trỏ ngăn xếp cho phù hợp và điều chỉnh được thực hiện khi nhập vào hàm. Bất kỳ cuộc gọi nào đến các chức năng khác đều có thể đẩy lên ngăn xếp mà không can thiệp vào khung ngăn xếp của chức năng này.

+0

vâng, thưa bạn, tôi đồng ý với bạn. Nhưng trong "spam()", "foo()" được gọi trước "", phải không? Sau đó, tôi nên đặt "int c" trong ngăn xếp cuộc gọi? Bên dưới địa chỉ trả lại? – Alcott

+3

Việc đặt trước ngăn xếp của các biến cục bộ thường được thực hiện một lần và cho tất cả khi bắt đầu thực hiện hàm. Vì vậy, a, b và c là tất cả không gian ngăn xếp trước khi foo được gọi. –

+0

OK. Nếu tôi gọi spam() và foo() trong chính (xem CẬP NHẬT) thì sao? Ngăn xếp cuộc gọi trông như thế nào? Bạn có nghĩa là kích thước của khung stack của một chức năng là tổng kích thước của người dân địa phương? – Alcott

Các vấn đề liên quan