§ 11. Классы памяти

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

1. Все переменные, которые вы просто объявляете и используете внутри функций, являются автоматическими (стековыми). Можно (но не нужно, потому что оно подразумевается) писать слово auto.

auto int foo = 0;

Примечание. В последних стандартах языка C++ слово auto утратило прежний смысл и теперь означает совсем другое.

Такие переменные хранятся на стеке (его размер небольшой), время жизни ограничено текущим блоком (говоря по-простому, фигурными скобками).

Фигурные скобки можно расставлять не только в конструкциях типа if или for, а в любых местах функции. Тогда переменная, объявленная в таком блоке, также будет ограничена его рамками.

{
    int foo = 0;
}
++foo; // Ошибка.

И есть очень странный эффект, когда в блоке перекрывается имя переменной, объявленной во внешнем блоке. Злоупотреблять этим, конечно, не стоит.

int foo = 0;
{
    int foo = 1;
}

2. Динамическая память, выделенная с помощью функции malloc() (и аналогичных), хранится в куче (heap). Она доступна отовсюду, где известен её адрес (указатель на неё). Заботы по управлению такой памятью ложатся на плечи программиста.

3. Статическая память — отдельная область, которая существует в течение жизни всей программы. Её интересная особенность в том, что переменные инициализируются нулями.

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

void print_next()
{
    static int i;
    printf("%d\n", i++);
}
print_next(); // 1
print_next(); // 2
print_next(); // 3

Статическая переменная, объявленная вне какой-либо функции, является глобальной (обычно слово static в таких случаях не пишут). Такие переменные доступны из любой функции, но пользоваться ими не следует.

#include <stdio.h>

static int foo = 0;

void print_foo()
{
    printf("%d\n", foo);
}

int main()
{
    extern int foo; // Необязательное объявление.
    foo += 7;
    print_foo(); // 7
    return 0;
}

В последнем примере слово extern (и последующее объявление) не является обязательным. Но есть и другой случай его использования. Если в одном cpp-файле переменные объявлены как глобальные статические (static вне функций), то для их использования в других cpp-файлах нужно их заново объявить со словом extern. Это будет сигналом, что память повторно выделять не нужно.

Небольшое замечание. Никогда не полагайтесь на порядок инициализации статических переменных.

4. Регистровые переменные помечаются словом register. Они размещаются непосредственно в регистрах процессора. Компилятор может проигнорировать вашу просьбу (у них бывают специальные эвристики, которые позволяют понять, что пользователь ничего не смыслит в устройстве процессоров и написании кода). Получить адрес такой переменной нельзя.

14 июня