logo

Компіляція програми на С: за лаштунками

Компіляція — це процес перетворення вихідного коду мови Сі в машинний код. Оскільки C є мовою середнього рівня, їй потрібен компілятор, щоб перетворити її на виконуваний код, щоб програму можна було запускати на нашій машині.

Під час компіляції програма C проходить наступні етапи:



процес компіляції в c

Процес компіляції в C

Як скомпілювати та запустити програму на C?

Нам спочатку знадобляться компілятор і редактор коду для компіляції та запуску програми C. Нижче наведено приклад машини Ubuntu з компілятором GCC.

Крок 1: Створення вихідного файлу C

Спочатку ми створюємо програму на C за допомогою редактора та зберігаємо файл як filename.c



використання операційної системи
  $ vi filename.c>

Ми можемо написати просту програму hello world і зберегти її.

Крок 2: Компіляція за допомогою компілятора GCC

Ми використовуємо наступну команду в терміналі для компіляції вихідного файлу filename.c

  $ gcc filename.c –o filename>

Ми можемо передати багато інструкцій компілятору GCC для різних завдань, таких як:



шаблони проектування в java
  • Опція -Wall вмикає всі попереджувальні повідомлення компілятора. Цей параметр рекомендується для створення кращого коду.
  • Параметр -o використовується для вказівки назви вихідного файлу. Якщо ми не використовуємо цю опцію, тоді буде створено вихідний файл із назвою a.out.

Якщо в нашій програмі на С немає помилок, буде згенеровано виконуваний файл програми на С.

Крок 3: Виконання програми

Після створення виконуваного файлу компіляції ми запускаємо згенерований виконуваний файл за допомогою наведеної нижче команди.

  $ ./filename>

Програма буде виконана, а результат буде показано в терміналі.

байтів до рядка python

Що відбувається в процесі компіляції?

Компілятор перетворює програму C на виконуваний файл. Щоб програма на С стала виконуваним файлом, проходять чотири етапи:

    Попередня обробка Зв'язування компіляції

Виконуючи наведену нижче команду, ми отримуємо всі проміжні файли в поточному каталозі разом із виконуваним файлом.

  $gcc -Wall -save-temps filename.c –o filename>

На наступному знімку екрана показано всі згенеровані проміжні файли.

Проміжні файли

Давайте один за одним подивимося, що містять ці проміжні файли.

1. Попередня обробка

Це перша фаза, через яку проходить вихідний код. Цей етап включає:

  • Видалення коментарів
  • Розширення макросів
  • Розширення включених файлів.
  • Умовне складання

Попередньо оброблений результат зберігається в ім'я файлу.i . Давайте подивимося, що всередині filename.i: використання $vi ім'я файлу.i

У наведеному вище вихідному файлі наповнено великою кількістю інформації, але зрештою наш код зберігається.

  • printf тепер містить a + b, а не add(a, b), тому що макроси розширено.
  • Коментарі видалені.
  • #include відсутній, натомість ми бачимо багато коду. Тож файли заголовків було розширено та включено до нашого вихідного файлу.

2. Складання

Наступним кроком є ​​компіляція filename.i та створення; проміжний скомпільований вихідний файл ім'я файлу.s . Цей файл знаходиться в інструкціях на рівні складання. Давайте розглянемо цей файл за допомогою $nano ім'я файлу.s команда терміналу.

яка різниця між мегабайтом і гігабайтом

Файл коду складання

Знімок показує, що це на мові асемблера, яку асемблер може зрозуміти.

3. Складання

На цьому етапі filename.s береться як вхідні дані та перетворюється на ім'я файлу.o монтажником. Цей файл містить інструкції на рівні машини. На цьому етапі лише існуючий код перетворюється на машинну мову, а виклики функцій, як-от printf(), не вирішуються. Давайте переглянемо цей файл за допомогою $vi filename.o

livecricket.is

Двійковий код

4. Посилання

Це остання фаза, на якій виконується пов’язування викликів функцій із їхніми визначеннями. Компонувальник знає, де реалізовані всі ці функції. Компонувальник також виконує деяку додаткову роботу, він додає додатковий код до нашої програми, який потрібен під час запуску та завершення програми. Наприклад, є код, який потрібен для налаштування середовища, як передача аргументів командного рядка. Це завдання можна легко перевірити за допомогою $size filename.o і $size назва файлу . За допомогою цих команд ми знаємо, як вихідний файл перетворюється з об’єктного файлу на виконуваний файл. Це через додатковий код, який Linker додає до нашої програми.

Примітка: GCC за замовчуванням виконує динамічне зв’язування, тому printf() динамічно зв’язується у програмі вище. Зверніться до цього , цього та цього, щоб дізнатися більше про статичне та динамічне зв’язування.