Відповіді:
=====> COMPILATION PROCESS <======
|
|----> Input is Source file(.c)
|
V
+=================+
| |
| C Preprocessor |
| |
+=================+
|
| ---> Pure C file ( comd:cc -E <file.name> )
|
V
+=================+
| |
| Lexical Analyzer|
| |
+-----------------+
| |
| Syntax Analyzer |
| |
+-----------------+
| |
| Semantic Analyze|
| |
+-----------------+
| |
| Pre Optimization|
| |
+-----------------+
| |
| Code generation |
| |
+-----------------+
| |
| Post Optimize |
| |
+=================+
|
|---> Assembly code (comd: cc -S <file.name> )
|
V
+=================+
| |
| Assembler |
| |
+=================+
|
|---> Object file (.obj) (comd: cc -c <file.name>)
|
V
+=================+
| Linker |
| and |
| loader |
+=================+
|
|---> Executable (.Exe/a.out) (com:cc <file.name> )
|
V
Executable file(a.out)
Попередня обробка C - це перший крок у компіляції. Він обробляє:
#define
заяви.#include
заяви.Мета пристрою - перетворити вихідний файл C у файл коду Pure C.
У блоці є шість кроків:
Він поєднує символи у вихідному файлі та утворює "TOKEN". Маркер - це набір символів, у яких немає "пробілу", "вкладки" та "нового рядка". Тому цю одиницю компіляції також називають "TOKENIZER". Він також видаляє коментарі, створює записи символьної таблиці та таблиці переселення.
Цей блок перевіряє синтаксис у коді. Наприклад:
{
int a;
int b;
int c;
int d;
d = a + b - c * ;
}
Вищевказаний код створить помилку розбору, оскільки рівняння не врівноважено. Цей блок перевіряє це внутрішньо, генеруючи дерево аналізатора наступним чином:
=
/ \
d -
/ \
+ *
/ \ / \
a b c ?
Тому цей блок також називають PARSER.
Цей блок перевіряє значення у висловлюваннях. Наприклад:
{
int i;
int *p;
p = i;
-----
-----
-----
}
Вищевказаний код породжує помилку "Присвоєння несумісного типу".
Цей блок не залежить від процесора, тобто є два типи оптимізації
Цей пристрій оптимізує код у таких формах:
Наприклад:
{
int a = 10;
if ( a > 5 ) {
/*
...
*/
} else {
/*
...
*/
}
}
Тут компілятор знає значення 'a' під час компіляції, тому він також знає, що умова if завжди відповідає дійсності. Отже, вона виключає іншу частину коду.
Наприклад:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = a + b + c;
/*
...
*/
}
можна оптимізувати наступним чином:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = x + c; // a + b is replaced by x
/*
...
*/
}
Наприклад:
{
int a;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
a = 10;
/*
...
*/
}
}
У наведеному вище коді, якщо "a" є локальним і не використовується в циклі, його можна оптимізувати наступним чином:
{
int a;
a = 10;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
}
}
Тут компілятор генерує код складання, щоб більш часто використовувані змінні зберігалися в регістрах.
Тут оптимізація залежить від процесора. Припустимо, якщо в коді є кілька стрибків, то вони перетворюються в один як:
-----
jmp:<addr1>
<addr1> jmp:<addr2>
-----
-----
Управління стрибає прямо.
Тоді останньою фазою є зв'язування (що створює виконуваний файл або бібліотеку). Коли виконується виконуваний файл, потрібні йому бібліотеки завантажуються.
Представлення ASCII:
[Source Code] ---> Compiler ---> [Object code] --*
|
[Source Code] ---> Compiler ---> [Object code] --*--> Linker --> [Executable] ---> Loader
| |
[Source Code] ---> Compiler ---> [Object code] --* |
| |
[Library file]--* V
[Running Executable in Memory]
Сподіваюся, це допоможе вам трохи більше.
Спочатку перейдіть до цієї схеми:
(img source->internet)
Ви робите фрагмент коду і зберігаєте файл (вихідний код), а потім
Попередня обробка : - Як випливає з назви, це не є складовою. Вони доручають компілятору виконати необхідну попередню обробку до фактичної компіляції. Ви можете викликати цю фазу заміни тексту або інтерпретувати спеціальні директиви препроцесора, позначені #.
Компіляція : - Компіляція - це процес, коли програма, написана однією мовою, перекладається на іншу цільову мову. Якщо є деякі помилки, компілятор виявить їх і повідомить про це.
Зберіть : - Код зібрання перетворюється на машинний код. Ви можете зателефонувати асемблеру спеціального типу.
Посилання : - Якщо для цього фрагмента коду потрібен інший вихідний файл, який потрібно зв'язати, лінкер пов'язує їх, щоб зробити його виконуваним файлом.
Є багато процесів, які відбуваються після нього. Так, ви здогадалися, саме тут приходить роль навантажувача:
Навантажувач : - Він завантажує виконуваний код у пам'ять; програма та стек даних створюються, реєстр стає ініціалізованим.
Маленька додаткова інформація: - http://www.geeksforgeeks.org/memory-layout-of-c-program/ , ви можете побачити макет пам'яті там.
Компілятор: Це програма, яка переводить мовну програму високого рівня в машинну мову. Компілятор розумніший, ніж асемблер. Він перевіряє всі види обмежень, діапазонів, помилок і т. Д. Але його час роботи програми більше і займає більшу частину пам'яті. Він має повільну швидкість. Тому що компілятор проходить всю програму, а потім переводить всю програму в машинні коди. Якщо компілятор працює на комп’ютері і виробляє машинні коди для одного комп’ютера, він відомий як самокомпілятор або резидентний компілятор. З іншого боку, якщо компілятор працює на комп'ютері і виробляє машинні коди для іншого комп'ютера, він відомий як крос-компілятор.
Linker: На мовах високого рівня зберігаються деякі вбудовані файли заголовків або бібліотеки. Ці бібліотеки заздалегідь визначені, і вони містять основні функції, необхідні для виконання програми. Ці функції пов'язані з бібліотеками програмою під назвою Linker. Якщо лінкер не знаходить бібліотеку функції, він повідомляє компілятору, а потім компілятор генерує помилку. Компілятор автоматично викликає лінкер як останній крок при складанні програми. Не вбудований у бібліотеки, він також пов'язує визначені користувачем функції з визначеними користувачем бібліотеками. Зазвичай більш тривала програма поділяється на менші підпрограми, що називаються модулями. І ці модулі повинні бути об'єднані для виконання програми. Процес поєднання модулів здійснює лінкер.
Навантажувач: Навантажувач - це програма, яка завантажує машинні коди програми в системну пам'ять. У галузі обчислювальної техніки навантажувач - це частина операційної системи, яка відповідає за завантаження програм. Це один із важливих етапів у процесі запуску програми. Тому що це вміщує програми в пам'ять і готує їх до виконання. Завантаження програми передбачає зчитування вмісту виконуваного файлу в пам'яті. Після завершення завантаження операційна система запускає програму, передаючи керування завантаженому програмному коду. Усі операційні системи, що підтримують завантаження програми, мають навантажувачі. У багатьох операційних системах завантажувач постійно зберігається в пам'яті.
У Вікіпедії повинні бути хороші відповіді, ось мої думки:
*
*
Зв'язувачі та навантажувачі Loaders з LinuxJournal пояснює цю концепцію чітко. Це також пояснює, як прийшло класичне ім'я a.out. (вихід асемблера)
Короткий підсумок,
c program --> [compiler] --> objectFile --> [linker] --> executable file (say, a.out)
ми отримали виконуваний файл, тепер передайте цей файл своєму другові або вашому клієнту, який потребує цього програмного забезпечення :)
коли вони запускають це програмне забезпечення, скажімо, ввівши його в командному рядку ./a.out
execute in command line ./a.out --> [Loader] --> [execve] --> program is loaded in memory
Після завантаження програми в пам'ять, керування передається цій програмі, роблячи ПК (лічильник програми), що вказує на першу інструкцію a.out
Він буде читати вихідний файл, який може мати тип .c або .cpp тощо, і переводить його в .o файл, який називається об'єктним файлом.
Він поєднує кілька .o файлів, які можуть бути створені для декількох вихідних файлів, у виконуваний файл (формат ELF у GCC). Існує два типи зв'язку:
Програма, яка завантажує виконуваний файл в основну пам'ять машини.
Для детального вивчення цих трьох етапів виконання програми в Linux, будь ласка, прочитайте це .
зміни компілятора перевіряють ваш вихідний код на наявність помилок і змінюють його в об'єктний код.це код, який працює операційна система.
Ви часто не пишете всю програму в одному файлі, тому лінкер посилається на всі файли об'єктного коду.
ваша програма не буде виконана, якщо вона не знаходиться в основній пам'яті
Linker & Interpreter - це взаємовиключні перекладачі, які отримують код за рядком та виконують рядок за рядком.
Компілятор Він перетворює вихідний код в об'єктний код.
Linker Він об'єднує декілька об'єктних файлів в один виконуваний програмний файл.
Навантажувач Він завантажує виконуваний файл у основну пам'ять.
Компілятор - це спеціальна програма, яка обробляє заяви, написані певною мовою програмування, і перетворює їх на машинну мову або "код", який використовує процесор комп'ютера
Компілятор перекладає рядки коду з мови програмування на машинну мову.
Linker створює зв'язок між двома програмами.
Завантажувач завантажує програму в пам'ять в основній базі даних, програмі тощо.
Компілятор: це системне програмне забезпечення, яке виправляє помилки програм, об’єктного файлу, повідомлень тощо
Linker: це системне програмне забезпечення, яке поєднує одне або декілька об'єктних файлів і можливий код бібліотеки або в якусь виправдану якусь бібліотеку, або в список помилок
Навантажувач: програма, яка завантажує виконуваний файл в основну пам'ять машини