Выполнение программ на С/С++
1. Этапы компиляции программ в С/С++
2. Стек вызовов
Этапы компиляции программ в С/С++
Этап №1: препроцессор
∙ Язык препроцессора – это специальный язык программирования, встроенный в C++.∙ Препроцессор работает с кодом на C++ как с текстом. Команды языка препроцессора называют директивами, все директивы начинаются со знака #.
∙ Директива #include позволяет подключать заголовочные файлы к файлам кода.
1. #include <foo.h> — библиотечный заголовочный файл,
2. #include "bar.h" — локальный заголовочный файл.
∙ Препроцессор заменяет директиву #include "bar.h" на содержимое файла bar.h.
Этап 2: компиляция
∙ На вход компилятору поступает код на C++ после обработки препроцессором.
∙ Каждый файл с кодом компилируется отдельно и независимо от других файлов с кодом.
∙ Компилируется только файлы с кодом (т.е. *.cpp).
∙ Заголовочные файлы сами по себе ни во что не компилируются, только в составе файлов с кодом.
∙ На выходе компилятора из каждого файла с кодом получается “объектный файл” — бинарный файл со скомпилированным кодом (с расширением .o или .obj).
Этап 3: линковка (компоновка)
∙ На этом этапе все объектные файлы объединяются в один исполняемый (или библиотечный) файл.
∙ При этом происходит подстановка адресов функций в места их вызова.
∙ По каждому объектному файлу строится таблица всех функций, которые в нём определены.
Этап 3: линковка (компоновка)
∙ На этапе компоновки важно, что каждая функция имеет уникальное имя.
∙ В C++ может быть две функции с одним именем, но разными параметрами.
∙ Имена функций искажаются (mangle) таким образом, что в их имени кодируются их параметры.
Аналогично функциям в линковке нуждаются глобальные переменные.
Этап 3: линковка (компоновка)
∙ Точка входа — функция, вызываемая при запуске программы. По умолчанию — это функция main.
Стек вызовов
Стек вызовов — это сегмент данных, используемый для хранения локальных переменных и временных значений. Не стоит путать стек с одноимённой структурой данных, у стека в C++ можно обратиться к произвольной ячейке. Стек выделяется при запуске программы. Стек обычно небольшой по размеру (4Мб).
Функции хранят свои локальные переменные на стеке. При выходе из функции соответствующая область стека объявляется свободной. Промежуточные значения, возникающие при вычислении сложных выражений, также хранятся на стеке.
При вызове функции на стек складываются:
1. aргументы функции,
2. адрес возврата,
3. значение frame pointer и регистров процессора.
Кроме этого на стеке резервируется место под возвращаемое значение. Параметры передаются в обратном порядке, что позволяет реализовать функции с переменным числом аргументов.
Адресация локальных переменных функции и аргументов функции происходит относительно frame pointer. Конкретный процесс вызова зависит от используемых соглашений (cdecl, stdcall, fastcall, thiscall).
|