Хранятся ли переменные стека C в обратном порядке?
Я пытаюсь понять, как C выделяет память в стеке. Я всегда думал, что переменные в стеке могут быть изображены как переменные-члены structs, они занимают последовательный, непрерывный блок байтов внутри стека. Чтобы проиллюстрировать эту проблему, которую я где-то нашел, я создал эту небольшую программу, которая воспроизвела это явление.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(int *i) {
int *_prev_int = (int *) ((long unsigned int) i - sizeof(int)) ;
printf("%dn", *_prev_int );
}
void main(void)
{
int x = 152;
int y = 234;
function(&y);
}
видишь, что я делаю? Предположим sizeof(int)
is 4: я ищу 4 байта за переданным указателем, так как это прочитало бы 4 байта до того, где int y
на абонента стек.
он не напечатал 152. Странно, когда я смотрю на следующие 4 байта:
int *_prev_int = (int *) ((long unsigned int) i + sizeof(int)) ;
и теперь он работает, печатает то, что в x
внутри стека вызывающего абонента. Почему?--4--> имеет меньший адрес, чем y
? Хранятся ли переменные стека вверх ногами?
2 ответов
организация стека полностью нет данных и конкретной реализации. На практике это зависит от большого количества компилятора (даже его версии) и флагов оптимизации.
некоторые переменные даже не сидят в стеке (например, потому, что они просто хранятся внутри некоторых регистров или потому, что компилятор оптимизировал их-например, путем вставки, постоянного сворачивания и т. д..).
кстати, у вас может быть некоторая гипотетическая реализация C, которая не использует стек (даже если я не могу назвать такую реализацию).
чтобы понять больше о стеках:
читайте wikipage на стеки вызовов, хвост называет, темы и продолжения
познакомьтесь сархитектура & набор команд (например, x86) & ABI, затем...
попросите компилятор показать код ассемблера и / или некоторые промежуточные представления компилятора. При использовании GCC скомпилировать простой код с
gcc -S -fverbose-asm
(чтобы получить ассемблерный кодfoo.s
при составленииfoo.c
) и попробовать несколько уровней оптимизации (по крайней мере-O0
,-O1
,-O2
....). Попробуйте также-fdump-tree-all
option (он сбрасывает сотню файлов, показывающих некоторые внутренние представления компилятора для вашего исходного кода). Обратите внимание, что GCC также обеспечивает обратный адрес builtinsчитать старую бумагу Аппеля на сбор мусора может быть быстрее, чем распределение стека, и понял вывоз мусора методы (поскольку им часто нужно проверять и, возможно, изменять некоторые указатели внутри фреймов стека вызовов). Чтобы узнать больше о GC, прочитайте руководство GC.
к сожалению, я не знаю языка низкого уровня (например, C, D, Rust, C++, Go,...) где стек вызовов доступен на уровне языка. Вот почему кодирование сборщика мусора для C сложно (так как GC-s нужно сканировать указатели стека вызовов)... Но смотри!--64-->консервативный GC Бема для очень практичного и прагматичного решения.
почти все архитектуры процессоров в настоящее время поддерживают инструкцию по манипуляции стеком(e.G LDM, STM instructions in ARM). Компиляторы С помощью этих инструментов stack. В большинстве случаев, когда данные помещаются в стек, указатель стека уменьшается (растет вниз) и увеличивается, когда данные появляются из стека.
Так это зависит от архитектуры процессора и компилятора, как реализован стек.