Пошаговая компиляция программы на языке c с помощью gcc.

Если вы когда-либо писали код на c, вы почти наверняка использовали gcc, clang или lcc. Эти программы берут удобочитаемый код и переводят его в машинный код для выполнения. Вам не нужно знать, как работают эти шаги, чтобы запустить программы на языке C, и вам может быть все равно, но если вы здесь, то я надеюсь, что вы захотите немного отодвинуть занавес, чтобы увидеть шаги, которые выполняются. чтобы оживить вашу тяжелую работу.

Первый шаг, который делает для нас gcc, — это прогон нашего кода через препроцессор. Самый распространенный шаг, который используется почти во всем коде на языке C, — это директива #include, которая указывает компилятору включить какой-либо другой код в наш файл. Часто это стандартный набор библиотек, такой как stdio.h или string.h, или, когда мы работаем над большими программами, это может быть наш собственный набор определений функций и констант. Препроцессор также расширяет макросы, завершающие код для компиляции. Если вы не используете макросы регулярно, прочитайте этот замечательный учебник по макросам от gcc gnu.

Вы можете увидеть, как выглядит этот код, используя команду gcc -E filename.c. В нашем примере кода библиотека stdio представляет собой большую часть нашего кода после предварительной обработки, а последние несколько строк показывают, что мы написали.

Как только gcc полностью расширил код с помощью препроцессора, пришло время превратить наш c в сборку — шаг компиляции. Ассемблерный код — это специфичные для машины инструкции, которые заставляют компьютер выполнять команды, составляющие нашу программу. В прежние времена, когда еще не было Паскаля, С и «современных» языков программирования, большая часть программирования была специфичной для системы и архитектуры. Это сделало написание программ для более широкой аудитории очень трудным, поскольку программы на ассемблере работают только на компьютерах, для которых они были запрограммированы.

Это шаг компиляции в процессе, который устраняет проблемы переносимости. Вот почему многие программы распространяются в виде исходного кода, а не скомпилированных исполняемых файлов. Затем исходный код может быть скомпилирован для работы в любой системе. Компилятор gcc содержит инструкции для большинства систем о том, как компилировать c в ассемблерный код, который работает на компилирующей машине.

Если вам интересно, как выглядит ассемблерный код, вы можете остановить gcc на этом шаге с помощью флага -S, и ваш файл filename.c выведет ассемблерный код в файле name.s: gcc -S filename.c

Предпоследней частью процесса является ассемблер. На этом этапе gcc берет ассемблерный код и превращает его в машинный код. Вы можете увидеть этот вывод, используя ассемблер GNU, as, в коде сборки с помощью команды as -o имя_файла.o имя_файла.s. Этот код очень близок к запуску и читается вашим компьютером, но в нем отсутствует последний шаг: компоновщик.

На практике программам требуются стандартные библиотеки и доступ к определенным системным функциям, таким как ввод/вывод. Компоновщик берет наш машинный код и корректно связывает его с требуемыми библиотеками, после чего завершает работу с завершенной компиляцией. Это вывод, который вы видите, когда не копаете глубже, а просто запускаете gcc filename.c.