Распределение памяти переменных

Я в замешательстве. Выполняется ли распределение автоматических, статических и глобальных переменных во время компиляции или времени выполнения?

Я знаю, что во время компиляции исходный код переводится на машинный язык.

Когда компилятор находит инструкцию типа int a; , он записывает инструкцию. Выполняются ли какие-либо дополнительные действия, такие как распределение памяти, во время компиляции?

Что произойдет, когда будет запущен файл .exe?

Будет ли компьютер (ОС) или компилятор выделять достаточную память для хранения целого числа во время выполнения или времени компиляции.

Также говорится, что адрес глобальной переменной является константой времени компиляции. Что это значит? Пожалуйста, помогите решить каждый вопрос, особенно последний.

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

 //global variable with internal linkage static int array[100]; 

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

 //global variable with internal linkage static int array[100] = { 1, 2, 3}; 

будет занимать место в исполняемом файле, поскольку оно инициализируется постоянными значениями во время компиляции. Таким образом, компилятор будет генерировать код в разделе data создаваемого файла сборки, который выделяет хранилище для массива. Затем компоновщик правильно компонует разделы раздела данных и кода всех файлов сборки, которые связаны с окончательным исполняемым файлом. Когда ОС загружает исполняемый файл в память, память для массива уже является частью памяти исполняемого файла «foot-print».

Автоматические переменные, так как они выделены в стеке во время выполнения кода, выделяются во время выполнения.

Также говорится, что адрес глобальной переменной – это константа времени компиляции.

Это немного вводит в заблуждение … в C вы не можете знать точный адрес памяти любых глобальных переменных, пока компоновщик не создал исполняемый файл, а ОС загрузила исполняемый файл в память. Единственный способ сделать это можно было бы, если бы вы вручную собрали файл и создали плоский двоичный файл, который был специально загружен в данный адрес операционной системой, но современные операционные системы не позволяют вам это делать. Вместо этого адреса глобальных переменных присваиваются владельцам мест, чтобы их можно было заменить правильными значениями, когда ОС загружает исполняемый файл во время выполнения. Поэтому, когда адрес памяти является «постоянным» в том смысле, что он не будет меняться со временем во время работы программы, его фактическое значение не назначается во время компиляции.

Это зависит от типа переменной:

  • переменные стека выполняются во время выполнения (хотя их размер известен во время компиляции, память стека зарезервирована только для записи функции, что делает его распределением времени выполнения). есть также специальное предостережение с этим, alloca выделяет из стека во время выполнения, хотя это похоже на его динамическую память кучи.

  • переменные кучи выделяются во время выполнения, как правило, через new / malloc , однако хранение указателей все равно может быть в стеке.

  • глобальные и статические переменные выделяются несколькими способами. инициализированные будут выделяться в двоичном виде компилятором с их начальным значением (или инициализатор будет вызываться при запуске для объектов). неинициализированные данные будут распределены через загрузчик ОС, читая PE, поэтому данные разделяются между различными сегментами, такими как .rdata , .data & .bss .

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

Компилятор создает объектный файл ( .obj под Windows, .o под Unix), который содержит больше, чем просто машинные инструкции, и не все конструкции на C ++ приводят к машинным инструкциям. Когда происходит выделение памяти (формально, по крайней мере), не указывается. На практике, поскольку число автоматических и динамических объектов неизвестно во время компиляции (поскольку функции могут быть рекурсивными), их можно выделить только во время компиляции, а компилятор будет генерировать код для этого (хотя обычно он будет выделять все автоматические переменные в функции с одной или двумя инструкциями в верхней части функции). С другой стороны, компилятор точно знает, сколько объектов со статическим временем жизни будет существовать. Все реализации, с которыми я знаком, генерируют записи загрузчика в объектном файле, что в конечном итоге приводит к тому, что системный загрузчик выделяет их как часть исходного изображения процесса при загрузке программы; в загруженной программе нет кода, который их распределяет. (Если инициализация не статична, будет введен код, который их инициализирует.)

У вас здесь куча вопросов. В C у вас есть память стека и память кучи. Глобалы находятся в куче. Все переменные non malloc, которые не являются глобальными, находятся в стеке. Думайте о стеке памяти как о памяти, которую вы создаете внутри своих функций. Каждый вызов функции добавляет еще один слой в ваш стек. Когда функция возвращается, возвращается немолочная память, которая была выделена внутри этой функции. Место хранения глобальной переменной никогда не изменяется, поэтому его позиция может быть статичной во время компиляции.

Когда компилятор находит инструкцию типа int a ;, он записывает инструкцию. Какие дополнительные вещи происходят, например, при распределении памяти во время компиляции?

Да, пространство зарезервировано для переменной в стеке.

Что произойдет, когда будет запущен файл .exe?

Слишком долго, чтобы на это ответить. Ограничьте свой вопрос.

Будет ли компьютер (os) или компилятор выделять достаточную память для хранения целого числа во время выполнения или времени компиляции.

Зависит от того, как вы выделяете память на свой код.

Также говорится, что адрес глобальной переменной – это константа времени компиляции. Что это значит?

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

Когда компилятор находит int a; оператор в функции, он пишет что-то вроде sub esp,sizeof(int) , и когда программа запускается и получает эту строку, она выделяет память.

Если это глобальная переменная, компилятор записывает resb , которая указывает ОС выделять память при загрузке программы.