C - это компилируемый язык. Его исходный код пишется с помощью любого редактора по выбору программиста в виде текстового файла, а затем он должен быть скомпилирован в машинный код.

Исходные файлы C по соглашению называются с расширением .c, и мы используем команду «gcc» для компиляции исходных файлов C. (GCC - это аббревиатура от GNU Compiler Collection, и это система компиляции, созданная проектом GNU.)

Четыре этапа компиляции: предварительная обработка, компиляция, сборка, компоновка.

Предварительная обработка:

Предварительная обработка - это первый шаг. Препроцессор подчиняется командам, начинающимся с символа # (так называемые директивы):

  • удаление комментариев
  • расширяющиеся макросы
  • расширение включенных файлов

Если вы включили файл заголовка, например #include ‹stdio.h›, он будет искать файл stdio.h и копировать файл заголовка в файл исходного кода.

Препроцессор также генерирует код макроса и заменяет символические константы, определенные с помощью #define, их значениями.

Компиляция:

Компиляция - второй шаг. Он принимает выходные данные препроцессора и генерирует язык ассемблера, промежуточный читаемый человеком язык, специфичный для целевого процессора.

Сборка:

Сборка - это третий этап компиляции. Ассемблер преобразует ассемблерный код в чистый двоичный код или машинный код (нули и единицы). Этот код также известен как объектный код.

Ссылка:

Связывание - это последний этап компиляции. Компоновщик объединяет весь объектный код из нескольких модулей в один. Если мы используем функцию из библиотек, компоновщик свяжет наш код с кодом этой библиотечной функции.

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

Теперь приступим к компиляции! В нашем примере мы будем использовать main.c в качестве исходного файла.

#include <stdio.h>
int main(void)
{
      printf("Hello, World!\n");
      return (0);
}

В командной строке введите команду «gcc main.c» и нажмите Enter. Если он успешно компилируется, снова отобразится приглашение оболочки. Если он не компилируется, будет отображаться сообщение (я) об ошибке.

vagrant@vagrant-ubuntu-trusty-64:~$ gcc main.c
vagrant@vagrant-ubuntu-trusty-64:~$ ls
a.out main.c

После компиляции main.c введите команду «ls», чтобы вывести список содержимого вашего каталога, и вы увидите исполняемый файл с именем a.out. Чтобы запустить программу, введите «./a.out» в командной строке и нажмите Enter. Ура, мы видим правильный ответ «Hello, World!» за которым следует новая строка.

vagrant@vagrant-ubuntu-trusty-64:~$ ./a.out
Hello, World!
vagrant@vagrant-ubuntu-trusty-64:~$

Если вы не хотите, чтобы ваш выходной файл назывался a.out, которое является именем выходного файла по умолчанию, вы можете указать другое имя выходного файла с параметром -o.

gcc -o <desired_output_filename> <source filename>

Давайте посмотрим на пример ниже, где мы хотим, чтобы выходной файл назывался main.

vagrant@vagrant-ubuntu-trusty-64:~$ gcc -o main main.c
vagrant@vagrant-ubuntu-trusty-64:~$ ls
main main.c
vagrant@vagrant-ubuntu-trusty-64:~$

Чтобы запустить основную программу, мы набираем «./main» в терминал.

vagrant@vagrant-ubuntu-trusty-64:~$ ./main
Hello, World!
vagrant@vagrant-ubuntu-trusty-64:~$

Если вы внесете изменения в свой код (т. е. внесете какие-либо изменения в исходный файл), вам потребуется сохранить и перекомпилировать.

В некоторых случаях исходный файл C не может быть успешно скомпилирован.

Прочтите сообщения об ошибках, чтобы узнать, как их исправить.

Ниже мы опустили точку с запятой в конце оператора printf.

#include <stdio.h>
int main(void)
{
      printf("Hello, World!\n")
      return (0);
}

В сообщении об ошибке отображается, что перед возвратом должна была стоять точка с запятой.

vagrant@vagrant-ubuntu-trusty-64:~$ gcc -o main main.c
main.c: In function 'main':
main.c:5:7: error: expected ';' before 'return'
       return (0);
       ^
vagrant@vagrant-ubuntu-trusty-64:~$

Если мы снова добавим точку с запятой…

#include <stdio.h>
int main(void)
{
      printf("Hello, World!\n");
      return (0);
}

… А затем перекомпилируйте, сообщение об ошибке исчезнет.

vagrant@vagrant-ubuntu-trusty-64:~$ gcc -o main main.c
vagrant@vagrant-ubuntu-trusty-64:~$ ./main
Hello, World!
vagrant@vagrant-ubuntu-trusty-64:~$

Даже если исходный файл компилируется, проверьте правильность вывода.

Вот пример исходного файла, который компилирует…

#include <stdio.h>
int main(void)
{
      printf("The sum of 9+2 is: %i\n", 10);
      return (0);
}

… Но вывод неверен.

vagrant@vagrant-ubuntu-trusty-64:~$ ./main2
The sum of 9+2 is: 10
vagrant@vagrant-ubuntu-trusty-64:~$

К сожалению, у нас есть ошибка из-за опечатки в исходном коде.

printf("The sum of 9+2 is: %i\n", 10);

Мы знаем, что 9 + 2 = 11, но компилятор выполнил код, указанный в приведенной выше строке. Он подставил число 10 в спецификатор формата% i.

Правильный код был бы:

#include <stdio.h>
int main(void)
{
      printf("The sum of 9+2 is: %i\n", 11);
      return (0);
}

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

Прочтите справочную страницу gcc для получения дополнительной информации. Удачного кодирования!