Какво се случва, когато напишете gcc main.c??

Какво се случва, когато въведете gcc main.c в терминала? За да разберете тази команда, първо се нуждаете от малко предистория. Нека започнем с първата част на командата, gcc. Gcc означава GNU Compiler Collection. Библиотеката gcc работи за различни езици, включително c. Gcc също е стандартен компилатор за повечето Unix операционни системи. Gcc е безплатен за използване от всеки и е създаден и поддържан от Фондацията за свободен софтуер (FSF).

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

И така, какво ще кажете за main.c? Е, main.c е името на файла, в който сме написали c код. Така че, когато извикаме файла, gcc main.c, това, което казваме на компютъра, е да използва програмата gcc, за да вземе файла main.c (с програма c, написана вътре) и компилирайте тази c програма в нещо, което може да се изпълни от компютъра. Процесът, през който преминават c файловете, отнема няколко стъпки. Нека да го разделим стъпка по стъпка.

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

Първата стъпка, предприета от програмата gcc, след като ѝ бъде казано с какъв файл искате да работите, е предварителната обработка. В тази стъпка на предварителна обработка се правят няколко промени в съдържанието на файла.

  1. Заместване на макрос — Компилаторът gcc замества всички имена на макроси във файла със стойността на този макрос.
  2. Премахване на коментар — При предварителната обработка коментарите се премахват, защото компютърът не се нуждае от нашите коментари, за да компилира кода.
  3. Заглавни файлове — Всяка c програма използва библиотека от предварително дефинирани функции, които можете да използвате, за да създадете вашата програма. Тези функции се записват в заглавните файлове. Препроцесорът gcc взема заглавните файлове във вашия c документ и записва информацията за заглавния файл в новия предварително обработен файл, така че да може да бъде прочетен правилно чрез следващите стъпки на компилацията.

В това изображение можете да видите отляво c кода, който сме написали. Това е кодът, който искаме от gcc да компилира. Когато напишем gcc main.c, файлът main.c влиза в стъпките за предварителна обработка на gcc и генерира файл, донякъде подобен на нашия оригинален файл, но с промените, които обсъдихме по-горе. Кодът вдясно показва какво е направил препроцесорът с нашия оригинален c кодов файл.

Компилация

Ролята на тази стъпка в процеса е да генерира код за сглобяване от предварително обработения файл. Страхотно, но какво е асемблерният код? Асемблиращият код е език от ниско ниво, което означава, че кодът действа директно с компютърната архитектура. Това е различно от езиците от по-високо ниво, които могат да бъдат по-преносими между различни компютърни платформи, докато асемблерният език може да бъде по-специфичен за машината, на която работите. Нашият gcc файл вече е преминал през две промени в процеса на компилиране. Предварителна обработка и компилация. Резултатът в този момент като файл, който е предварително обработен и след това е превърнат в код за асемблиране. Файлът в този момент изглежда много различно и е драстично променен.

Отляво е нашият предварително обработен код от горната стъпка. Когато стъпката на компилиране е завършена, предварителният файл вече е превърнат в код за асемблиране. Кодът за сглобяване вдясно съответства на предварително обработения файл, показан вляво (направен от оригиналния c файл, който написахме.

Асемблер

На този етап от процеса имаме предварително обработен файл и променен в код за асемблиране. Но проблемът сега е, че дълбоко в компютъра той всъщност използва различен вид код, за да управлява нещата. Компютърът работи с двоичен код. Двоичните числа се състоят само от 0 и 1. този код се нарича обектен код и по същество е нечетлив за човек, но компютърът може да разбере морето от 0 и 1 доста добре.

Отляво е нашият асемблиращ код от стъпката по-горе. След това кодът на сглобяването се прехвърля в двоичен код. Двоичният код е това, което компютърът използва под всичко, за да изчисли и изпълни всяко действие, което му е поискано. Можете да видите двоичния код вдясно, 10100110100. Двоичният код трябва да се използва от компютъра, а не от програмиста.

Линкер

Последната стъпка в процеса се нарича линкер или процес на свързване. Както казах преди, много c файлове съдържат връзки към различни библиотеки с предварително дефинирани функции. Библиотеките са пълни с различни предварително създадени функции, които можете да извиквате и използвате, без изобщо да виждате основния код, който дефинира функцията. С помощта на библиотека можете да извикате функция, да я използвате и да получите резултат, без изобщо да знаете действителния код, който кара функцията да работи.

Всъщност има два вида връзки, които процесите на свързване могат да използват. Единият се нарича статично свързване. Статичното свързване е, когато компилаторът копира всички файлове с обектен код, които сме създали по този начин, и в процеса на свързване прави копие на всички библиотеки, които сме използвали в нашия оригинален c код като изображение, което го поставя в изпълнимо изображение. Тази стратегия за свързване отнема повече дисково пространство и памет и вероятно е малко по-бърза от другия метод за свързване, който този процес може да използва. Този тип свързване обаче се счита за малко по-преносим между компютърни платформи, тъй като с този метод не се нуждаете от библиотеките на вашия компютър, защото те са налични в изпълнимия образ, който този процес създава.

Другият метод за свързване се нарича динамично свързване. Динамичното свързване поставя ИМЕТО на библиотеката в изпълнимия образ. Освен това при свързването на dymaic действителното свързване към библиотеката не се осъществява, докато изображението не бъде стартирано и завършеният изпълним файл не бъде поставен в паметта на компютъра. Динамичното свързване също има предимството, че позволява на множество програми да споделят копие на библиотеката.

Етапът на линкера взема всички наши двоични файлове, създадени в предишната стъпка, и съхранява тези двоични файлове заедно с изпълним образ на всички библиотеки (статично свързване) или изпълним образ, съдържащ само имената на библиотеките (динамично свързване).

Успех!

Вече взехме нашия готов документ с код (main.c) и го подложихме на пълния процес на компилация: предварителна обработка, компилация, асемблер и линкер. Резултатът е изпълним файл, който компютърът действително може да използва и обработва и да получи резултат от него.

За други езици процесът на компилиране е малко по-различен, така че тази статия се отнася главно до пътя, който дадена програма c минава, докато се компилира за използване.