Это стандартный вопрос интервью:
Динамическое выделение памяти
Распределяется ли память во время выполнения с использованием calloc()
, malloc()
и друзей.Иногда ее также называют «кучной» памятью, хотя она не имеет ничего общего со структурой данных кучи ref .
int * a = malloc(sizeof(int));
Память кучипостоянный до вызова free()
.Другими словами, вы управляете временем жизни переменной.
Автоматическое выделение памяти
Это то, что обычно называют «стековой» памятью, и выделяется при вводе новой области (обычнокогда новая функция помещается в стек вызовов).Как только вы выходите из области видимости, значения автоматических адресов памяти не определяются, и это ошибка для доступа к ним .
int a = 43;
Обратите внимание, что область действия не обязательно означает функцию.Области могут быть вложены в функцию, и переменная будет находиться в области видимости только внутри блока, в котором она была объявлена.Также обратите внимание, что место, где выделяется эта память, не указано.(В вменяемой системе это будет в стеке или регистры для оптимизации)
Статическое выделение памяти
Распределение во время компиляции и время жизни переменнойв статической памяти время жизни программы .
В C статическая память может быть выделена с помощью ключевого слова static
.Область действия - только единица компиляции.
Все становится интереснее , когда ключевое слово extern
считается .Когда переменная extern
определена как , компилятор выделяет для нее память.Когда extern
переменная объявлена , компилятор требует, чтобы переменная была определена в другом месте.Неспособность объявить / определить extern
переменные вызовет проблемы со связыванием, в то время как неудача в объявлении / определении static
переменных вызовет проблемы с компиляцией.
в области видимости файла, ключевое слово static является необязательным (вне функции):
int a = 32;
Но не в области действия функции (внутри функции):
static int a = 32;
Технически, extern
и static
являются двумя отдельными классами переменных в C.
extern int a; /* Declaration */
int a; /* Definition */
Регистровая память
Последний класс памяти является переменными регистра.Как и ожидалось, переменные регистра должны быть размещены в регистре процессора, но решение фактически остается за компилятором.Вы не можете превратить переменную регистра в ссылку, используя address-of.
register int meaning = 42;
printf("%p\n",&meaning); /* this is wrong and will fail at compile time. */
Большинство современных компиляторов умнее, чем вы, выбираете, какие переменные следует помещать в регистры:)
Ссылки:
Замечания о статическом распределении памяти
Несколько смущает утверждение, что статическая память выделенаво время компиляции, особенно если мы начнем считать, что машина компиляции и хост-машина могут не совпадать или даже не иметь одинаковую архитектуру.
Лучше подумать , что выделение статической памяти обрабатывается компилятором , а не , выделенным во время компиляции . Например, компилятор может создать большой раздел data
в скомпилированном двоичном файле, и когда программа загружается в память, адрес в сегменте data
программы будет использоваться в качестве расположения выделенной памяти. Это имеет явный недостаток - делать скомпилированный двоичный файл очень большим, если используется много статической памяти. Можно написать двоичный файл размером в несколько гигабайт, сгенерированный из менее чем полдюжины строк кода. Другим вариантом для компилятора является внедрение кода инициализации, который будет распределять память каким-либо другим способом до выполнения программы. Этот код будет отличаться в зависимости от целевой платформы и ОС. На практике современные компиляторы используют эвристику, чтобы решить, какой из этих параметров использовать. Вы можете попробовать это самостоятельно, написав небольшую C-программу, которая выделяет большой статический массив из элементов 10k, 1m, 10m, 100m, 1G или 10G. Для многих компиляторов размер двоичного файла будет расти линейно с размером массива, и после определенной точки он снова сократится, поскольку компилятор использует другую стратегию размещения.