Переменные в стеке "статически распределены"?

Я читал эту статью и увидел следующее: "В этой статье предполагается, что вы уже знаете и понимаете, по крайней мере, в основном, как работает карта памяти в системе GNU/Linux, и особенно разница между памятью, статически выделяемой в стеке, и памятью, динамически выделяемой в куча ".

Это смутило меня, потому что я думал, что стек и куча распределяются динамически, то есть распределяются только в случае необходимости, а глобальные переменные и переменные, объявленные как "статические" внутри функции, размещаются статически, то есть всегда распределяются.

Например, если у меня есть

void f() {
    int x = 1;
    ...
}

значение 1 помещается в стек, а указатель стека увеличивается только в том случае, если вызывается функция f(). Точно так же, если у меня есть

void f() {
    int x = malloc(1 * sizeof(int));
    ...
}

эта куча памяти выделяется только при вызове f(). Однако, если у меня есть "int x = 1;" в глобальном разделе программы или "static int x = 1;" в теле функции, каждый раз, когда я запускаю эту программу, эта память будет выделяться в разделе данных со значением 1.

Я не прав насчет этого?

3 ответа

Решение

Сам стек статически размещен. Переменные, размещенные в стеке, приходят и уходят, поскольку поток управления входит и выходит из области видимости.

Статические переменные инициализируются только один раз, даже если оператор инициализации находится внутри тела функции.

Проверьте пример википедии:

#include <stdio.h>

void func() {
    static int x = 0; 
    /* x is initialized only once across five calls of func() and
      the variable will get incremented five 
      times after these calls. The final value of x will be 5. */
    x++;
    printf("%d\n", x); // outputs the value of x
}

int main() { //int argc, char *argv[] inside the main is optional in the particular program
    func(); // prints 1
    func(); // prints 2
    func(); // prints 3
    func(); // prints 4
    func(); // prints 5
        return 0;
}

Стек - это в основном большой статически распределенный массив с подвижным указателем, который начинается в его начале. Когда вы вызываете функцию (начиная с main), указатель перемещается (создает кадр стека), а пространство в кадре стека разбивается на части и отдается локальным переменным (сколько у вас локальных переменных определяет размер стека фрейма вашей функции будет). Таким образом, локальные переменные являются своего рода динамическими (они появляются только после ввода функции), но стек имеет статический размер. Если вы выделите для него сверхбольшую структуру или будете использовать слишком много рекурсии, вы выйдете за пределы конца, и ОС унесет вас вниз - явление, известное как переполнение стека. ( значок переполнения значок на самом деле иллюстрирует это. Серый контейнер внизу представляет статический массив, которым является стек. Оранжевые прямоугольники - это фреймы, созданные вызовами функций. Как и при правильном переполнении стека, кадры переполняют контейнер и бум - ваша программа мертва. Тот факт, что кадры идут вверх, иллюстрирует другую, довольно специфическую вещь в стеке: новые кадры имеют более низкие адреса, чем старые, поэтому стекопотоки действительно происходят в начале массива стека, а не в его конце (если вы не думаете о массивах как начиная с самого большого индекса и заканчивая 0).)

Стек выделяется в единицах кадра стека.

  • Когда функция вызывается, для нее выделяется кадр стека,
  • Когда функция возвращается, ее кадр стека исчезает,

А стек помогает хранить аргументы функций и локальные переменные.

После того, как функция получит свой стековый фрейм, да, внутри стекового фрейма функция будет использовать его байты по мере необходимости.


Динамическое выделение стека как в куче

Если вы хотите выделить память в стеке как в куче, вы можете использовать alloca() от <alloca.h>, это быстрее, чем куча, но в большинстве случаев вам это не нужно, у него есть недостатки, поэтому в общем случае это не рекомендуется.


Опишите распределение стека в другом контексте, чтобы было более понятно:

  • С точки зрения Linux thread(кстати, каждый процесс имеет 1 поток при создании по умолчанию как основной поток), стек имеет фиксированный размер и выделяется при создании потока (2 МБ для IA-32, 32 МБ для IA-64, по умолчанию), и вы можете изменить размер по умолчанию при необходимости. Таким образом, вы можете сказать, что это исправлено и статично.
  • С точки зрения function в потоке или процессе кадр стека выделяется для него из памяти стека потока, когда функция запускается, и кадр стека исчезает, когда функция завершается.
  • С точки зрения нестатического local variable внутри функции переменная выделяется из стекового фрейма функции по мере необходимости динамически.

Так что, если вы называете это статическим или динамическим, вы решаете.

Другие вопросы по тегам