Tôi đang cố gắng hiểu sâu hơn về cách hoạt động của các hoạt động cấp thấp của ngôn ngữ lập trình và đặc biệt là cách chúng tương tác với OS / CPU. Có lẽ tôi đã đọc mọi câu trả lời trong mọi chủ đề liên quan đến ngăn xếp / đống ở đây trên Stack Overflow và chúng đều rất tuyệt vời. Nhưng vẫn còn một điều mà tôi vẫn chưa hiểu hết.
Hãy xem xét hàm này trong mã giả có xu hướng là mã Rust hợp lệ ;-)
fn foo() {
let a = 1;
let b = 2;
let c = 3;
let d = 4;
// line X
doSomething(a, b);
doAnotherThing(c, d);
}
Đây là cách tôi giả định ngăn xếp trông giống như trên dòng X:
Stack
a +-------------+
| 1 |
b +-------------+
| 2 |
c +-------------+
| 3 |
d +-------------+
| 4 |
+-------------+
Bây giờ, mọi thứ tôi đã đọc về cách ngăn xếp hoạt động là nó tuân thủ nghiêm ngặt các quy tắc LIFO (nhập sau cùng, xuất trước). Cũng giống như kiểu dữ liệu ngăn xếp trong .NET, Java hoặc bất kỳ ngôn ngữ lập trình nào khác.
Nhưng nếu đúng như vậy, thì điều gì sẽ xảy ra sau dòng X? Bởi vì rõ ràng, điều tiếp theo chúng ta cần là làm việc với a
và b
, nhưng điều đó có nghĩa là OS / CPU (?) Phải bật ra d
và c
trước tiên để quay lại a
và b
. Nhưng sau đó nó sẽ tự bắn vào chân, bởi vì nó cần c
và d
ở dòng tiếp theo.
Vì vậy, tôi tự hỏi những gì chính xác xảy ra đằng sau hậu trường?
Một câu hỏi liên quan khác. Hãy xem xét chúng ta chuyển một tham chiếu đến một trong các hàm khác như sau:
fn foo() {
let a = 1;
let b = 2;
let c = 3;
let d = 4;
// line X
doSomething(&a, &b);
doAnotherThing(c, d);
}
Theo cách tôi hiểu mọi thứ, điều này có nghĩa là các tham số trong doSomething
về cơ bản đang trỏ đến cùng một địa chỉ bộ nhớ như a
và b
trong foo
. Nhưng một lần nữa, điều này có nghĩa là không có cửa sổ bật lên nào cho đến khi chúng ta đến a
vàb
diễn ra.
Hai trường hợp đó khiến tôi nghĩ rằng tôi đã không hoàn toàn hiểu chính xác cách hoạt động của ngăn xếp và cách nó tuân thủ nghiêm ngặt các quy tắc LIFO .
LIFO
có nghĩa là bạn chỉ có thể thêm hoặc xóa các phần tử ở cuối ngăn xếp và bạn luôn có thể đọc / thay đổi bất kỳ phần tử nào.