Стек, используемый в таких языках, как C, не является типичным LIFO. Он называется стеком, потому что он используется в аналогично для LIFO: при вызове процедуры в стек помещается новый кадр. Кадр обычно содержит локальные переменные и информацию о бухгалтерском учете, например, где можно вернуться. Точно так же, когда процедура возвращается, ее фрейм сбрасывается со стека.
В этом нет ничего волшебного. Компилятор (а не операционная система) выделяет регистр, который будет использоваться как stack pointer - назовем его SP
. По соглашению, SP
указывает на ячейку памяти следующего свободного стека слова:
+----------------+ (high address)
| argument 0 |
+----------------+
| argument 1 |
+----------------+
| return address |
+----------------+
| local 0 |
+----------------+
| local 1 |
+----------------+ +----+
| free slot | <-------------- | SP |
+----------------+ (low address) +----+
протолкнуть значение в стек, мы делаем что-то вроде этого (в псевдо-сборки):
STORE [SP], 42 ; store the value 42 at the address where SP points
SUB SP, 1 ; move down (the stack grows down!) to the next stack location
В тех случаях, когда обозначение [SP]
считывается как «содержимое ячейки памяти, к которой относится SP
пунктов». Некоторые архитектуры, в частности x86, предоставляют команду push
, которая выполняет как хранение, так и вычитание. Чтобы поместить (и отбросить) n верхние значения в стеке, мы просто добавляем n в SP
*.
Теперь предположим, что мы хотим получить доступ к полем local 0
выше. Достаточно легко, если наш CPU имеет режим адресации base+offset! Предположим, SP
указывает на свободный слот, как на картинке выше.
LOAD R0, [SP+2] ; load "local 0" into register R0
Обратите внимание, как мы не Лопните local 0
из стека первых, потому что мы можем ссылаться на любое поле, используя его смещение от указателя стека.
В зависимости от архитектуры компилятора и машины может быть другой регистр, указывающий на область между локалями и аргументами (или около того). Этот регистр, обычно называемый frame pointer, остается фиксированным, когда указатель стека перемещается.
Я хочу подчеркнуть тот факт, что, как правило, операционная система вообще не участвует в манипулировании стеком. Ядро выделяет исходный стек и, возможно, отслеживает его рост, но оставляет нажатие и выскакивание значений в пользовательской программе.
* Для простоты я предположил, что размер машинного слова 1 байт, поэтому мы вычитаем 1 из SP. На 32-битной машине нажатие слова на стек означает вычитание (по крайней мере) четырех байтов.
Зачем вы хотите это сделать? Возможно, есть еще одно, лучшее решение вашей проблемы. – Mikkel
Это, по крайней мере, LIFO, в C. –