Я не очень хорошо разбираюсь в компьютерах, поэтому мои вопросы довольно наивны.
Я узнал, что компиляция кода C резервирует определенное пространство памяти в стеке в основной памяти во время компиляции.
Затем,
Почему исполняемый файл работает, если он скомпилирован на одном компьютере и скопирован на другой компьютер?
Если компиляция резервирует определенное место в памяти ОЗУ, то ограничивается ли количество исполняемых файлов (или компиляции) размером ОЗУ?
Если компиляция резервирует место в оперативной памяти, почему исполняемый файл занимает намного больше места на диске, чем текстовый файл .C перед компиляцией?
Спасибо
Компиляция не резервирует место во время компиляции. Он генерирует код, который делает это при загрузке программы. Программу можно загрузить на другой компьютер.
На любой из ваших вопросов нет простого ответа в один абзац. Если вы действительно хотите в этом разобраться, пройдите курс NAND to Tetris.
Это существенное различие между компиляторами и интерпретаторами. Компиляторы генерируют код, который можно выполнить позже, потенциально на другом компьютере. Интерпретаторы немедленно выполняют код.
После компиляции исполняемый код вашей программы и некоторые данные, которые могут быть известны во время компиляции. Этот код и фиксированные данные (исполняемый файл может быть довольно большим, если таких данных много) загружаются в память (код может быть загружен в память, защищенную от записи). Затем операционная ищет информацию о том, по какому адресу находится первая инструкция программы, и запускается оттуда. Затем, когда выполняются вызовы, локальные переменные функции (есть на большинстве компьютеров) помещаются в стек.
@Barnar Не совсем, если у вас есть статические переменные, они занимают место в вашем исполняемом файле (попробуйте большой статический массив, если хотите убедиться в этом сами)
@PepijnKramer Таким образом, он резервирует место на диске, а не в оперативной памяти. Оперативная память становится зарезервированной после загрузки исполняемого файла
Читайте внимательно, не ВСЯ память, необходимая программе, зарезервирована на диске. только память, необходимая статическим переменным. Локальные переменные (в большинстве систем) попадают в стек, а динамически выделенная память (new/delete/std::make_unique) оказывается где-то в оперативной памяти (обычно называемой кучей).
Стек не резервируется компилятором во время компиляции. Он зарезервирован в том смысле, что компилятор вставляет определенные команды и директивы в исполняемый файл, чтобы стек был зарезервирован при загрузке/запуске исполняемого файла.
См. выше. Оперативная память не резервируется (то есть становится недоступной для других исполняемых файлов) во время компиляции. Он зарезервирован, когда исполняемый файл загружается/выполняется.
Это не обязательно правда. Во многих случаях исполняемый файл меньше кода. Но это может зависеть от многих факторов, таких как способ написания кода, формат исполняемого файла, включенные в него метаданные и расположение памяти. Иногда исполняемый файл будет содержать целые разделы, заполненные нулями, которые могут быть определены одной строкой кода.
В общем, у компилятора (в сочетании с компоновщиком, если мы хотим быть педантичными) есть только одна «простая» задача — взять входные файлы (код) и сгенерировать выходной файл (ы) — исполняемый файл. То есть - это создание файлов, которые только занимают место в файловой системе. Другие вещи могут происходить только тогда, когда среда (ОС) загружается и что-то с ними делает (загружает, выполняет).
Вопрос № 2 также вызван незнанием виртуальной памяти.
брать входные файлы (код) и генерировать выходные файлы -> Или, как мне однажды сказали, компилятор берет удобочитаемый код и превращает его в машиночитаемый код
@NathanOliver Мне довелось увидеть исходный код, который вообще не читался человеком :)
Пространство не резервируется во время компиляции. Во время компиляции генерируются инструкции, которые при выполнении во время выполнения занимают место в стеке.
Например, когда вы объявляете переменную в своем коде:
int x = 5;
Компилятор выдаст инструкции, которые помещают в стек 4 байта (допустим, это размер int
). Но это происходит во время выполнения. Это пространство резервируется при достижении этой строки кода во время выполнения. Предупреждение здесь заключается в том, что оптимизирующий компилятор может делать здесь все, что угодно, и может фактически не выделять пространство стека.
Это работает, когда вы копируете исполняемый файл на другую машину, потому что резервирование стека будет происходить на этой машине во время выполнения кода.
Количество исполняемых файлов, которые могут быть запущены одновременно, будет зависеть от объема памяти. Обратите внимание, что многие ОС будут переключать память между оперативной памятью и доступным жестким диском, если у вас закончится память. Это увеличивает количество исполняемых файлов, которые можно запускать, но при этом система обычно сильно замедляется.
Краткий ответ: Однако хочет. Стандарт C не заставляет вас что-либо делать и даже не имеет стека. На практике некоторые операционные системы имеют настройки по умолчанию при запуске исполняемых файлов на любом языке. Если вы хотите узнать больше, вот пример о Rust, который объясняет, что происходит до запуска вашей
main()
функции. На самом деле в вашем исполняемом файле много чего происходит.