2012-02-12 30 views
7

Từ http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/Các biến cục bộ chức năng được truy cập từ ngăn xếp như thế nào?

Dưới đây là trình tự các bước diễn ra khi một chức năng là gọi:

  1. Các địa chỉ của lệnh vượt ra ngoài gọi hàm được đẩy vào stack. Đây là cách CPU ghi nhớ nơi để đi sau khi trả về hàm .
  2. Phòng được tạo trên ngăn xếp cho loại trả về của hàm. Đây chỉ là một trình giữ chỗ cho bây giờ.
  3. CPU nhảy vào mã của hàm.
  4. Đầu hiện tại của ngăn xếp được giữ trong một con trỏ đặc biệt được gọi là khung ngăn xếp.
  5. Mọi thứ được thêm vào ngăn xếp sau thời điểm này được coi là "cục bộ" đối với hàm.
  6. Tất cả đối số chức năng được đặt trên ngăn xếp.
  7. Hướng dẫn bên trong của hàm bắt đầu thực hiện.
  8. Biến cục bộ được đẩy lên ngăn xếp khi chúng được xác định.

Tôi không chắc chắn về cách hoạt động của điểm số 6. Nếu tất cả các đối số hàm được đặt trên ngăn xếp, chúng được truy cập như thế nào?

Nếu ví dụ, có ba đối số a, bc và được đặt trên ngăn xếp như thế này từ trên

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

Bây giờ những gì sẽ xảy ra khi chức năng muốn truy cập c? ab có xuất hiện không?

+1

dường như không thể đối với tôi rằng bước 3 xảy ra trước 6: cần có * bên trong * mã chức năng cơ thể về đánh giá của người gọi. Vô lý! – CapelliC

Trả lời

1

Không, không. Con trỏ ngăn xếp (thường là số đăng ký esp) trỏ tới a, esp+8h trỏ đến b, esp+16h trỏ đến c và cứ tiếp tục như vậy. Không cần a để xuất hiện.

Lưu ý rằng đây là chi tiết triển khai. Bạn không nên lo lắng về điều này. Số tôi đã cho là hoàn toàn lý thuyết, trên một số kiến ​​trúc giảm dần địa chỉ được đưa ra cho các tham số thứ hai, trên những người khác theo cách khác xung quanh. Không có gì đảm bảo điều này xảy ra.

EDIT: Dường như với tôi như vậy không phải là nguồn thông tin đáng tin cậy. Nó nói về ngăn xếp và đống, nhưng đây là những chi tiết triển khai, và thậm chí có thể không có ở đó.

Không có ràng buộc trong tiêu chuẩn cho mọi thứ cần được triển khai thông qua ngăn xếp. Ví dụ: tôi có mã sau được tạo:

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 

Vì vậy, bạn thấy đấy, không có ngăn xếp ở đó. Thời gian chạy có quyền truy cập trực tiếp vào các phần tử: dword ptr [x], v.v.

+0

Nhưng nói chung một ngăn xếp được thực hiện theo cách mà bạn không thể truy cập một phần tử bằng bất kỳ cách nào khác ngoài việc thực thi 'top()' .. tôi đang thiếu gì? – Lazer

+1

@Lazer: Không. Ngăn xếp là cấu trúc dữ liệu nơi bạn có thể thêm và xóa các phần tử khỏi đầu ngăn xếp trong thời gian không đổi. Không ai nói bạn không thể truy cập ngẫu nhiên chúng. – ybungalobill

0

Nó sử dụng con trỏ ngăn xếp và địa chỉ tương đối để chỉ ra c.

11

Ngăn xếp là một ngăn xếp ẩn dụ ẩn dụ. Hãy nhớ rằng nó vẫn là RAM, vì vậy bạn có thể truy cập từng địa chỉ mà không cần popping phần còn lại, nếu bạn biết những gì bạn đang tìm kiếm.

Kể từ kích thước tự động biến được biết đến tại thời gian biên dịch - dấu biên dịch offset cho mỗi biến, bù đắp được xác định từ nơi phần biến tự động trên ngăn xếp bắt đầu [hoặc người đứng đầu của chồng, cả hai đều hợp lệ và cụ thể việc triển khai phụ thuộc có thể phụ thuộc vào kiến ​​trúc], và nó truy cập chúng bằng cách chỉ: start + offset cho mỗi lần bù của biến.

+0

Trên mọi nền tảng bạn có khả năng gặp phải, đó là một chồng ẩn dụ. Nếu nó là một ngăn xếp thực sự chỉ có các hoạt động push và pop, thì chức năng sẽ phải bật các tham số ra nếu nó cần chúng "không đúng thứ tự". –

+0

nơi trong bộ nhớ là các offset được lưu trữ? –

+0

@CaisManai Khoản bù được biết tại thời gian biên dịch và không cần lưu trữ trong bộ nhớ. – amit

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