Câu trả lời:
Khung ngăn xếp là khung dữ liệu được đẩy lên ngăn xếp. Trong trường hợp ngăn xếp cuộc gọi, khung ngăn xếp sẽ đại diện cho một lệnh gọi hàm và dữ liệu đối số của nó.
Nếu tôi nhớ chính xác, địa chỉ trả về hàm được đẩy lên ngăn xếp trước, sau đó là đối số và khoảng trắng cho các biến cục bộ. Cùng nhau, họ tạo ra "khung", mặc dù điều này có thể phụ thuộc vào kiến trúc. Bộ xử lý biết có bao nhiêu byte trong mỗi khung và di chuyển con trỏ ngăn xếp tương ứng khi các khung được đẩy và bật ra khỏi ngăn xếp.
Có một sự khác biệt lớn giữa ngăn xếp cuộc gọi cấp cao hơn và ngăn xếp cuộc gọi của bộ xử lý.
Khi chúng ta nói về ngăn xếp cuộc gọi của bộ xử lý, chúng ta đang nói về việc làm việc với các địa chỉ và giá trị ở mức byte / từ trong cụm hoặc mã máy. Có "ngăn xếp cuộc gọi" khi nói về các ngôn ngữ cấp cao hơn, nhưng chúng là một công cụ gỡ lỗi / thời gian chạy được quản lý bởi môi trường thời gian chạy để bạn có thể ghi lại những gì đã xảy ra với chương trình của bạn (ở mức cao). Ở cấp độ này, những thứ như số dòng và phương thức và tên lớp thường được biết đến. Vào thời điểm bộ xử lý nhận được mã, nó hoàn toàn không có khái niệm nào về những điều này.
Nếu bạn hiểu rất rõ về stack thì bạn sẽ hiểu bộ nhớ hoạt động như thế nào trong chương trình và nếu bạn hiểu cách bộ nhớ hoạt động trong chương trình, bạn sẽ hiểu cách lưu trữ chức năng trong chương trình và nếu bạn hiểu cách lưu trữ chức năng trong chương trình, bạn sẽ hiểu chức năng đệ quy hoạt động như thế nào và nếu bạn hiểu chức năng đệ quy hoạt động như thế nào bạn sẽ hiểu cách trình biên dịch hoạt động và nếu bạn hiểu cách trình biên dịch hoạt động, tâm trí của bạn sẽ hoạt động như trình biên dịch và bạn sẽ gỡ lỗi bất kỳ chương trình nào rất dễ dàng
Hãy để tôi giải thích cách stack hoạt động:
Trước tiên, bạn phải biết cách các hàm được biểu diễn trong ngăn xếp:
Heap lưu trữ các giá trị được phân bổ động.
Stack lưu trữ giá trị phân bổ và xóa tự động.
Hãy hiểu ví dụ:
def hello(x):
if x==1:
return "op"
else:
u=1
e=12
s=hello(x-1)
e+=1
print(s)
print(x)
u+=1
return e
hello(4)
Bây giờ hãy hiểu các phần của chương trình này:
Bây giờ hãy xem stack là gì và các phần stack là gì:
Phân bổ ngăn xếp:
Hãy nhớ một điều: nếu điều kiện trả về của bất kỳ hàm nào được thỏa mãn, bất kể nó có tải các biến cục bộ hay không, nó sẽ ngay lập tức trở về từ ngăn xếp với khung ngăn xếp của nó. Điều đó có nghĩa là bất cứ khi nào bất kỳ hàm đệ quy nào được thỏa mãn điều kiện cơ sở và chúng ta đặt trả về sau điều kiện cơ sở, điều kiện cơ sở sẽ không chờ để tải các biến cục bộ được đặt trong phần khác của chương trình. Nó sẽ ngay lập tức trả về khung hiện tại từ ngăn xếp theo đó khung tiếp theo hiện đang ở trong bản ghi kích hoạt.
Xem điều này trong thực tế:
Giao dịch của khối:
Vì vậy, bây giờ bất cứ khi nào một hàm gặp câu lệnh return, nó sẽ xóa khung hiện tại khỏi ngăn xếp.
Trong khi trả về từ ngăn xếp, các giá trị sẽ được trả lại theo thứ tự ban đầu mà chúng được phân bổ trong ngăn xếp.
hello()
đã được gọi đệ quy hello()
mà sau đó (một lần nữa) được gọi đệ quy hello()
và khung toàn cầu là hàm ban đầu được gọi là đầu tiên hello()
?
Một bọc nhanh chóng. Có lẽ ai đó có một lời giải thích tốt hơn.
Một ngăn xếp cuộc gọi bao gồm 1 hoặc nhiều khung ngăn xếp. Mỗi khung ngăn xếp tương ứng với một cuộc gọi đến một chức năng hoặc thủ tục chưa kết thúc bằng trả về.
Để sử dụng khung ngăn xếp, một luồng giữ hai con trỏ, một được gọi là Con trỏ ngăn xếp (SP) và luồng còn lại được gọi là Con trỏ khung (FP). SP luôn trỏ đến "đỉnh" của ngăn xếp và FP luôn trỏ đến "đỉnh" của khung. Ngoài ra, luồng cũng duy trì bộ đếm chương trình (PC) trỏ đến lệnh tiếp theo sẽ được thực thi.
Sau đây được lưu trữ trên ngăn xếp: biến cục bộ và thời gian, tham số thực tế của lệnh hiện tại (thủ tục, hàm, v.v.)
Có các quy ước gọi khác nhau liên quan đến việc làm sạch ngăn xếp.
"Một ngăn xếp cuộc gọi bao gồm các khung ngăn xếp ..." - Wikipedia
Khung stack là một thứ mà bạn đặt trên stack. Chúng là các cấu trúc dữ liệu chứa thông tin về chương trình con cần gọi.
Các lập trình viên có thể có câu hỏi về khung stack không theo nghĩa rộng (rằng đó là một thực thể singe trong ngăn xếp chỉ phục vụ một lệnh gọi hàm và giữ địa chỉ trả về, đối số và biến cục bộ) nhưng theo nghĩa hẹp - khi thuật ngữ stack frames
này được đề cập trong bối cảnh của các tùy chọn trình biên dịch.
Cho dù tác giả của câu hỏi có ý nghĩa hay không, nhưng khái niệm khung stack từ khía cạnh của các tùy chọn trình biên dịch là một vấn đề rất quan trọng, không được đề cập trong các câu trả lời khác ở đây.
Ví dụ: trình biên dịch Microsoft Visual Studio 2015 C / C ++ có các tùy chọn sau liên quan đến stack frames
:
GCC có những điều sau đây:
Trình biên dịch Intel C ++ có các phần sau:
có bí danh sau:
Delphi có tùy chọn dòng lệnh sau:
Theo nghĩa cụ thể đó, từ phối cảnh của trình biên dịch, khung ngăn xếp chỉ là mã nhập và thoát cho thường trình , đẩy một neo vào ngăn xếp - cũng có thể được sử dụng để gỡ lỗi và xử lý ngoại lệ. Các công cụ gỡ lỗi có thể quét dữ liệu ngăn xếp và sử dụng các neo này để sao lưu, trong khi định vị call sites
trong ngăn xếp, tức là để hiển thị tên của các hàm theo thứ tự chúng được gọi là phân cấp. Đối với kiến trúc Intel, nó là push ebp; mov ebp, esp
hoặc enter
cho mục nhập và mov esp, ebp; pop ebp
hoặc leave
để thoát.
Đó là lý do tại sao rất quan trọng để hiểu cho lập trình viên về khung stack là gì khi nói đến các tùy chọn trình biên dịch - bởi vì trình biên dịch có thể kiểm soát việc có tạo mã này hay không.
Trong một số trường hợp, khung ngăn xếp (mã nhập và thoát cho thường trình) có thể được trình biên dịch bỏ qua và các biến sẽ được truy cập trực tiếp thông qua con trỏ ngăn xếp (SP / ESP / RSP) thay vì con trỏ cơ sở thuận tiện (BP / TRÒ CHƠI / RSP). Điều kiện bỏ qua khung stack, ví dụ:
Bỏ qua các khung ngăn xếp (mã nhập và thoát cho thường trình) có thể làm cho mã nhỏ hơn và nhanh hơn, nhưng nó cũng có thể ảnh hưởng tiêu cực đến khả năng của trình gỡ lỗi để quay lại dữ liệu trong ngăn xếp và hiển thị nó cho lập trình viên. Đây là các tùy chọn trình biên dịch xác định theo điều kiện nào một hàm nên có mã nhập và thoát, ví dụ: (a) luôn luôn, (b) không bao giờ, (c) khi cần (chỉ định các điều kiện).
Khung stack là thông tin đóng gói liên quan đến một cuộc gọi chức năng. Thông tin này thường bao gồm các đối số được truyền cho hàm th, các biến cục bộ và nơi để trả về khi kết thúc. Bản ghi kích hoạt là tên gọi khác của khung stack. Bố cục của khung ngăn xếp được xác định trong ABI bởi nhà sản xuất và mọi trình biên dịch hỗ trợ ISA phải tuân theo tiêu chuẩn này, tuy nhiên sơ đồ bố trí có thể phụ thuộc vào trình biên dịch. Nói chung kích thước khung ngăn xếp không bị giới hạn nhưng có một khái niệm gọi là "vùng đỏ / được bảo vệ" để cho phép các cuộc gọi hệ thống ... vv thực hiện mà không can thiệp vào khung ngăn xếp.
Luôn có SP nhưng trên một số ABI (ví dụ của ARM và PowerPC) là tùy chọn. Các đối số cần được đặt trên ngăn xếp chỉ có thể được xử lý bằng SP. Việc khung stack có được tạo cho một lệnh gọi hàm hay không phụ thuộc vào loại và số lượng đối số, các biến cục bộ và cách các biến cục bộ được truy cập nói chung. Trên hầu hết các ISA, đầu tiên, các thanh ghi được sử dụng và nếu có nhiều đối số hơn các thanh ghi dành riêng để truyền các đối số thì chúng được đặt trên ngăn xếp (Ví dụ x86 ABI có 6 thanh ghi để truyền các đối số nguyên). Do đó, đôi khi, một số chức năng không cần đặt khung ngăn xếp trên ngăn xếp, chỉ cần địa chỉ trả về được đẩy lên ngăn xếp.