C ++: объявления переменных функций, как это работает внутри? - PullRequest
2 голосов
/ 13 декабря 2010

Это долго беспокоило меня: допустим, у меня есть функция:

void test(){
    int t1, t2, t3;
    int t4 = 0;
    int bigvar[10000];
    // do something
}

Как компьютер управляет выделением памяти для переменных?

Я всегда думал, что пространство переменных сохраняется в .exe, который затем будет читать компьютер, это правильно? Но, насколько я знаю, массив bigvar не занимает 10000 int элементов пространства в .exe, так как он неинициализирован. Так как же работает распределение памяти при вызове функции?

Ответы [ 3 ]

9 голосов
/ 13 декабря 2010

Локальные переменные, подобные этим, обычно реализуются с использованием стека процессора .Это означает, что единственное, что нужно сделать компилятору, это вычислить размер каждой переменной и сложить их вместе.Общая сумма - это сумма, на которую нужно изменить указатель стека при входе в функцию и вернуть обратно при выходе.Затем к каждой переменной обращаются со своим относительным смещением в этот блок памяти в стеке.

Ваш код при компиляции в Linux выглядит в ассемблере x86 следующим образом:

test:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $40016, %esp
        movl    $0, -4(%ebp)
        leave
        ret

Выше константа $ 40016 - это пространство, необходимое для четырех 32-битных целых чисел t1, t2, t3 и t4, а оставшиеся 40000 байтов составляют массив из 10000 элементов bigvar.

0 голосов
/ 13 декабря 2010

На некоторых старых компиляторах я встречал поведение статического размещения массива.Это означает, что он выделяет для него память при загрузке программы и использует это пространство после этого.Такое поведение небезопасно (см. Ответ Сергея), и я не ожидаю, что оно будет разрешено в соответствии со стандартами, но я столкнулся с ним в дикой природе.(Я не помню, какой это был компилятор.)

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

Другая правильная реализация состоит в том, что переменная, найденная в стеке, является указателем, и что компилятор выполняет выделение и освобождение (предположительно безопасным способом исключения) вкапот.Это сэкономит место в стеке (которое должно быть выделено до запуска программы и не может быть легко расширено для архитектур x86), а также весьма полезно для стандарта C VLA (массив переменной длины, он же бедный mans std :: vector)

0 голосов
/ 13 декабря 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...