Защо графичните библиотеки се нуждаят от линкер. Помощник за начинаещ в работата на линкера. Име на елементите за съхранение: какво е в средата на C файла

В типична система анонимна програма е мигновено победител. Работата на скин програмата е да съхранява различни функции, които могат да влязат в склада на "стандартната" C-библиотека (напр.printf() , malloc() , пиша ()и т.н.).

Подобно на скин програма срещу стандартната библиотека, това означава, че скин програма, като правило, отмъщава за собственото си копие на библиотеката. Жалко е, че се довежда до ирационален подбор на ресурси. Oskіlki библиотека С є спилна, rozumnіshe ще може да работи така, schob skin програмапопита на глобално копие на библиотеката, а немистила її копие. Такъв pіdkhіd е a є іlka іn vag, і і іn't аnоst є sanіnіі є sаnоmіya salоsistemnyh ресурсів іv'yatі.

Статично оформление срок "статично свързан" означава, че програмата и библиотеката са били комбинирани за помощ на линкера за един час до процеса на свързване. В този ред връзката между програмата и библиотеката се фиксира и инсталира под часа на процеса на свързване, така че преди програмата да бъде разработена. Krіm іnshoy, tse също означава, че можете да промените tsey zv'azokв противен случай, като за допълнителна рекомбинация на програмата с нова версия на библиотеката.

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

Статичните свързани програми са свързани с архиви на обекти (библиотеки ), за да можете да разширите a. Пример за такъв набор от обекти е стандартната библиотека libc.a.

Динамично оформление срок "динамично свързан" означава, че програмата е дневна библиотекане бяха обединени с помощта на линкер за един час към процеса на свързване. Natomist, линкерът поставя информацията във файла за свързване, който по свой начин ви позволява да знаете, че в някакъв обектен модул, който е разделен, кодът и някакъв динамичен линкер (изпълнение на линкер) е виновен Tse означава, че връзката между програмата и обекта, който се разделя, се инсталира в часа на програмата, а самата, в самия кочан на началото, се извършва търсене и подреждане на необходимите обекти, които се разделят навън.

Този тип програма се наричачастично обвързан изпълним файл (частично обвързан изпълним файл) , фрагментите, които имат, са разрешени в пълното споразумение, т.е. линкерът в процеса на свързване не е показал всички посочени символи в програмата с правилния код от библиотеката. Zamіst tsgogo, komonuvalnik vkazuє,якому сама обекти, които са разделени, познават функциите, извиквани от програмата. В резултат на това самият процес на свързване се извършва всяка година, още в момента на програмирането.

Динамично свързаните програми са свързани с обекти, които са разделени, с разширения т.н. Пример за такъв обект е стандартната C библиотека libc.so.

За да разкажете набор от инструменти за тези, кой тип оформление може да се зададе - статично или динамично - победна опция командна линия QCC комунални услуги. След това тази опция ще промени разширението (a или така).

Добавяне на код в процеса на роботизирани програми При такъв подход функциите, които се извикват от програмите, ще бъдат присвоени само на етапа на извикването. Tse nada dodatkovі mozhlivosti.

Нека да разгледаме задната част на диска с драйвера на робота. Драйверът стартира, тества устройството и показва харддиск. Тогава драйверът динамично улавя модула io-blk, заданията за обработка на дискови блокове, т.к. беше разкрито блокиране на прикачени файлове. Тъй като драйверът отказва достъп до диска на ниво блок, той показва два дяла на диска: дял DOS и дял QNX4. Не променяйте rozmіr на драйвера харддиск, до новото стартиране драйверите не се включват файлови системи. За един час работа на системата, драйверът може да открие две разделяния (DOS и QNX4) и едва след това да завладее vіdpovіdnі модули на файловите системи fs-dos.so и fs-qnx4.so.

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

Как обектите, които се разделят, са победители За да разберем как се разделят програмата на победоносните обекти, е необходимо първо да разгледаме формата на модифицирания модул, а след това и последователността от тихи етапи, през които програмата преминава при стартиране. ELF формат В QNX Neutrino OS е възприет така нареченият изпълним и свързващ формат, ELF, който в момента е приет в SVR4 Unix системите. Форматът ELF не само опростява създаването на библиотеки, които се разпространяват, но също така разширява възможностите за динамично ангажиращи модули за един час работа и програми.

На фиг. 7.1 Отчитане на ELF-файл за две изяви: представяне на оформлението и представяне на визуализация. Подаването на свързване, тъй като то е победно в процеса на свързване на програми или библиотеки, си струвасекции в средата на обектния файл. Раздели за покриване на по-голямата част от информацията в този файл: данни, инструкции, информация за персонализиране, идентификатори, данъчна информация и др.сегменти .

В процеса на свързване на програмата или библиотеката ще бъдат на помощ ядосани секции, които могат да имат същите атрибути, които се трансформират в сегменти. По правило всички секции, които отмъщават данни, разпознати за гледане или "само за четене", са подредени в един сегменттекст, и даннитеBSS да бъдат сглобени в сегментданни. Ци сегментите се наричатzavantazhuvalnymi сегменти (сегменти за натоварване) вонята е виновна, че е уловена в паметта по време на процеса на създаване. Други раздели, като например информация за идентификатори и данъчна информация, се комбинират с т.з.сегменти, които не се зареждат (сегменти без натоварване) .

tsієї statti.

Организиране на таблици със символни имена в асемблер.

Тази таблица съдържа информация за символите и техните значения, избрани от асемблера в часа на първото преминаване. Преди таблицата със символични имена асемблерът преминава към друг пасаж. Нека да разгледаме методите за организиране на таблици със символични имена. Даваме таблица като асоциативна памет, която събира набор от двойки: символът на името е значението. Асоциативната памет на im'ya може да види нейното значение. Замяната на името и стойността може да бъде зададена на име и стойност.

След сглобяване.

Таблицата със символни имена се представя като резултат от първото преминаване към масив от двойки име-стойност. Търсенето на необходим символ се определя от последния преглед на таблицата, документите няма да бъдат признати за валидни. Подобен начин да го направите е лесен за програмиране, но е практически осъществим.

Сортиране по имена.

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

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

Кеш кодиране.

При този метод на базата на изходната таблица ще се създаде кеш функция, която извежда имената в цялото число в пространството на K-1 (фиг. 5.2.1, а). Кеш функцията може да бъде например функцията за умножаване на всички редове на името, представено от ASCII кода, или друга функция, като например даване на еднаква стойност. След това се създава кеш таблицата, за да се изчистят редовете (слотовете). В реда на кожата имената се сортират (например по азбучен ред), които могат да имат същата стойност на кеш функцията (фиг. 5.2.1 b) или номера на слота. Ако има n имена на знаци в кеш таблицата, тогава средният брой имена в слота на кожата става n/k. Когато n = k, стойността на изискваното символно име е необходимо само едно търсене. Като промените начина, можете да промените размера на таблиците (броя на слотове) и скоростта на заявката. Zv'yazuvannya, че zavantazhennya. Програмата може да се използва като поредица от процедури (подпрограма). Асемблер по прищявка излъчванеедна процедура след друга, създаване обектни модулитози спомен за тях в паметта. За otrimannya vykonuvannogo dvіykovoy код поради buti знам, че po'yazanівсички процедури за излъчване.

Функциите на комуникацията и завантаженията се основават на специални програми, както се наричат линкери, които наричат ​​завантажувачи, редактори на връзкиили линкери.


По този начин, за пълна готовност преди края на уикенда, програмата се нуждае от две стъпки (фиг. 5.2.2):

● превод, реализиран от компилатора или от асемблера на скин рутина с метода за премахване на обектния модул. Часът на излъчване ще се промени отвънфилмът е включен празникезик, какви могат да бъдат различни команди и записи;

● Свързване на обектни модули, които се конкатенират от линкера за извличане на двоичния код. Окрема превод на уикански процедури възможни помилванияили необходимостта от промяна на процедурите. В тези случаи е необходимо повторно свързване на всички обектни модули. Oskіlki zv'yazuvannya vіdbuvaєtsya по-богат, по-нисък превод, vykonannya tsikh два krokіv (излъчване и zv'yazuvannya) спестява един час с допълнителни програми. Това е особено важно за програми, които покриват стотици хиляди модули. В операционните системи MS-DOS, Windows и NT модулите на обекта могат да имат разширението ".obj", а разширенията ".exe" могат да се използват в програмите близнаци, които се използват. В UNIX система, обектните модули могат да имат разширение ".o", но двойните програми, които могат да бъдат изградени, не могат.

Функции на линкер.

Преди началото на първия монтажен проход, локаторът на адреса на командата е зададен на 0. Това кратко е еквивалентно на надбавката, която е обектният модул за часа на смяната на средата с адрес 0.

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


Нека да разгледаме спецификата на оформлението на някои обектни модули (фиг. 5.2.3 а), независимо дали са в средата с адрес 0 и започват от командата BRANCH до командата MOVE в същия модул. Преди да стартира програмата, линкерът поставя обектните модули в главната памет, образувайки двойния код, който се преобразува. Звучи малко разделение на паметта, което започва от нулев адрес, печели за векториране, пренаписване операционна системаи други цели.

За това, както е показано на фиг. 5.2.3, b програмите започват не от нулев адрес, а от адрес 100. Модулът на Skin обект на фиг. 5.2.3 и заемането на много адресно пространство, обвиняват проблема с пренаписването на паметта. Командите на Mustache няма да бъдат изпратени в паметта чрез неправилно адресиране. Например, командата call-click на обектния модул B (фиг. 5.2.3 b), която е включена в средата с адрес 300 на обектния модул A (фиг. 5.2.3, a), не може да бъде намерена по две причини:

● командата CALL B е в средата с друг адрес (300, а не 200); ● Процедурата на кожата Oskіlki се превежда okrem, асемблерът не може да определи как да вмъкне адреса в командата CALL В. Такъв проблем се нарича проблемът с безчувственото послание.Причините за негодувание се използват с помощта на линкер, който обединява повече адресни пространства на обектни модули в едно линейно адресно пространство, за което:

● бъдеща таблица на обектните модули и техните дожини;

● въз основа на дадената таблица задайте адреси на модула на обекта на кожата;

към паметтаи добавете константа на изместване към кожата на тях, като правилен адрес на модула (в тази посока 100);

● познава командите, които се използват преди процедуритекойто вмъква адреса на тези процедури в тях.
По-долу е дадена таблица с обектни модули (Таблица 5.2.6), подкана за първия. Дават им имената си, дожина и пощенски адреси на скин модула. Таблица 5.2.6 и на фиг. 5.2.3, чл. структура на обектен модул. Обектните модули се състоят от следните части:

име на модула,деяк Допълнителна информация(например последните части на модула, датата на сглобяване);

списък със задачи за символния модул(символични имена) наведнъж с их стойности. Към тези символи могат да се добавят и други модули. Моят асемблерен програмист, с помощта на директивата PUBLIC, определя кои имена на символи се спазват от входните точки;

списък със символи, които са победители,както е присвоено на други модули. Списъкът също има символични имена, които са избрани от други команди на машината. Това позволява на конструктора да вмъкне правилните адреси на команди, така че да изпише правилните имена. Поради тази причина една процедура може да извика други независимо преведени процедури, като извика (с помощта на директивата EXTERN) имената на процедурите, които се извикват. За определени типове входни точки едни и същи съобщения се комбинират в една таблица;

машинни команди и константи;

движение на речника.Преди командите, yakі m_stat адреси на паметта, можете да добавите движеща се константа (div. small. 5.2.3). Самият линкер не може да бъде дефиниран, като думи за отмъщение на машинните команди и като - константи. Следователно в тази таблица има информация за тези адреси, които трябва да бъдат преместени. Възможно е да има таблица с битове, където битът може да бъде потенциално преместен към адреса, или изричен списък с адреса, който трябва да бъде преместен;

край на модула, адреси на кочани също контролна суманазначаването на помилвания, увеличаване на часа за четене на модула. Видмитимо, що машинни команди и константиЕдна част от обектния модул, сякаш трябва да бъде заснета в паметта за виконнаня. Други части от vikoristovuyutsya и vіdkidayutsya komonuvalnik към програмите за кочана vykonannya. Повече компоненти використ двепътека:

● всички обектни модули се четат по ред и ще има таблица с имена и имена на съществуващите модули, както и таблица със символи, която се добавя към входните точки на тези съществуващи съобщения;

● След това модулите се четат отново, преместват се в паметта и се свързват. Относно програмите за преместване. Проблемът с придвижването като в паметта на програмите се обяснява с факта, че тяхното преместване като в адресните таблици става милостиво. За да похвалите решението за преместване на програми, е необходимо да знаете момента на окончателното обаждане символични именас абсолютно адреси физическа памет.

Един час похвално решениесе извиква моментът на обозначаване на адреса в основната памет, което потвърждава символичното име. Іsnuyut raznі вариант за часа priynyattya решение schodo zv'yazuvannya: ако спелтапрограма, ако програмата да се излъчва, да се сглобява, да се оплитаили ако команда,да отмъсти за адреса, печеля.Методът за гледане напред показва символични имена с абсолютни физически адреси. Следователно не е възможно преместването на програмите след обаждането.

При свързване могат да се видят два етапа:

първоетап, якому символични именаобади ми се виртуални адреси.Ако линкерът poov'yazuє okrem_ адресно пространство на обектни модули в едно линейно адресно пространство, ще създам виртуално адресно пространство;

другиетап, кога виртуални адресиобади ми се физически адреси.Само след друга операция процесът на комуникация ще бъде завършен. Необходимо програми за промяна на съзнаниетоє наличието на механизъм, който ви позволява да промените виртуалния адрес към адреса на основната физическа памет (посетете друга стъпка). Към такива механизми лежат:

● раздори отстрани. Адресно пространство, изображения на фиг. 5.2.3, за замяна на виртуалните адреси, които вече са присвоени и съответстват на символичните имена A, B, C и D. Всички физически адреси трябва да бъдат изтрити от страничната таблица. Следователно, за да преместите програмата в основната памет, е достатъчно да промените само таблицата на страните, а не самата програма;

● Виктория регистър за преместване.Този регистър е посочен на физическия адрес на кочанстрийминг програми, които са заснети от операционната система, преди да преместите програмата. За допълнителна хардуерна поддръжка регистърът за преместване се дава на целия адрес на паметта, на първо място, смрадът ще бъде взет в паметта. Процесът на преместване е „видим“ за кожата програма на користувача. Особеността на механизма: при изглед на цепката отстрани, цялата програма трябва да се премести отгоре. Ако има регистри (или сегменти на паметта, например на процесори Intel) за преместване на код и преместване на данни, тогава тази програма трябва да се движи като два компонента;

● механизъм животнов памет на личилник на отборите. В случай на различен механизъм, когато програмата се премести в основната памет, само няколко команди се актуализират. Програмата, всички букви към паметта на това, което е свързано с името на командите (в противен случай, в абсолютни стойности, например, писмото до регистрите на приложенията във introduction-vivoda в абсолютни адреси), се нарича независима от позицията програма.Такава програма може да се разпространява на всяко място от виртуалното адресно пространство без промяна на адреса. Динамично обаждане.

По-добър начин за обаждане може да бъде един отличителен белег: zv'yazok z usima процедури, трябват програми, инсталирайте на cob роботизирани програми. По-рационален начин за свързване на компилацията от процедури, заглавия динамичен zv'azuvannyam polyagaє vstanovlennі zv'yazku s кожна процедура в часа на първия уикенд. На първо място имаше стагнации в системата MULTICS.

Динамична комуникация в систематаMULTICS. За кожата програмазакопчалки сегмент за повикване,премахнете информационния блок за процедурата по кожата (фиг. 5.2.4).

Информацията включва:

● думата "Непряк адрес", запазена за виртуалния адрес на процедурата;

● име на процедурата (EARTH, FIRE и т.н.), тъй като е взето от изглеждащите ланцетни знаци. При динамично свързване извикванията на процедурите на входния mov се преобразуват в команди, които за допълнително непряко адресиране се препращат към думата „Индиректен адрес” на изходния блок (фиг. 5.2.4). Компилаторът също ще запомни същата дума грешен адрес,или специален набор от битове,какъв вид повикване е прекъсване на системата (напр пасти).Какво следва:

● линкерът да знае имената на процедурите (например EARTH) и да пристъпва към търсене в локалната директория за компилирана процедура с такива имена;

● На известните процедури се присвоява виртуален адрес "EARTH Addresses" (звук в горния сегмент), тъй като се записва върху невалидния адрес, както е показано на фиг. 5.2.4;

● командата, сякаш призовава за помилване, отново е победоносна. Tse позволява на програмата да продължи работата на робота за един месец, няма да спре, докато системата не се рестартира. Всички предстоящи обаждания преди процедурата EARTH ще бъдат отменени без извинения, но в сегмента, където е заменена думата "Indirect addresses", вече се показва виртуалният адрес "EARTH addresses". В този ранг асемблерът на задачите е по-малък от същия, ако първо се извика процедурата за двойка. Следващото извикване на линкера не е необходимо.

Динамично повикване в системата Windows.

За свързване се използват библиотеки, които са динамично свързани (Dynamic Link Library - DLL), както и процедури и (или) данни. Библиотеките са проектирани като файлове с разширения ".dll", ".drv" (за библиотеки с драйвери - библиотеки с драйвери) и ".fon" (за библиотеки с шрифтове - библиотеки с шрифтове). Те позволяват техните процедури и данни да бъдат разпределени между различни програми (процеси). Най-голямата форма на DLL е библиотека, която се състои от набор от процедури, които са вкоренени в паметта, до които програмите имат достъп един час наведнъж. Като пример на фиг. Фигура 5.2.5 показва няколко процеса за модифициране на DLL файл за замяна на процедури A, B, C и D. Програми 1 и 2 използват процедура A; програма 3 - процедура D, програма 4 - процедура B.
DLL файлът ще бъде линкер от набор от входни файлове. Принципът на подсказване е подобен на подсказването на победоносния двоен код. Забележете, че когато се създаде DLL файл, към линкера се предава специален флаг, за да информира линкера за създаването на DLL. DLL файловете са изградени с набор от библиотечни процедури, които може да са необходими на много процесори. Типичните приложения на DLL файлове са процедури, получени от системната библиотека щракнете върху windowsи страхотни графични библиотеки. DDL уики файловете позволяват:

● Защитете пространството в паметта на диска. Например, сякаш библиотеката е свързана с програма за скин, ако тя е победител, тогава тази библиотека ще се появи в богати двойни програми в паметта и на диска. Ако трябва да се копират DLL файлове, тогава библиотеката на кожата се регистрира веднъж на диск и веднъж в паметта;

●простете за актуализирането на библиотечните процедури и освен това zdіysniti novlennya, navit след това, тъй като програмите, които използват, са компилирани и pov'yazanі;

● за коригиране на извиненията, установени от начина на разпространение на нови DLL файлове (например чрез Интернет). С това не е необходимо да работите с ежедневните промени в основните двоични програми. Основен авторитетмежду DLL файл и двойна програма, която е свързана, зависи от факта, че DLL файлът:

● не може да стартира и работи самостоятелно;

● премахнете друга информация от заглавката;

● Може да има няколко допълнителни процедури, които не са свързани с процедурите в библиотеката, например процедури за виждане на паметта и управление на други ресурси, които се изискват от DLL файла. Програмата може да се свързва от DLL файл по два начина: с помощта на имплицитно свързване и чрез помощта на явно свързване. В имплицитно свързванепрограмата koristuvach е статично свързана със специален файл, наречен библиотека за импортиране.

В противен случай тази библиотека се създава от обслужваща програма полезностчрез вилица информация за пеенеот DLL файл. Библиотеката за импортиране чрез свързващия елемент позволява на програмата да премахне достъпа до DLL файла, като в този случай той може да бъде свързан към библиотеката за импортиране. Windows системас имплицитна връзка към контролната програма, която е zavantazhuetsya за vikonannya. Системата показва, че DLL файловете са премахнати от програмата и че всички необходими файлове вече се прехвърлят от паметта. Всеки ден файловете са небрежно zavantazhuyutsya на една гатанка.

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

В изрична връзкаНямате нужда от библиотеки за импортиране и не е необходимо да импортирате DLL файлове за една нощ с програмата Koristuvach. Програма Natomist Koristuvalnitskaya:

● zdіysnyuє vysnyuє vyklik директно pіd час на работа, schob инсталирайте връзки от DLL файла;

● ще използваме допълнителни връзки, за да изберем адресите на процедурите, от които се нуждаем;

● След като следващата програма създаде окончателно обаждане за отваряне на връзката от DLL файла;

● Ако оставащият процес отваря връзка от DLL файл, този файл може да бъде изтрит от паметта. След това посочете, че процедурата за динамично свързване DLL файлове Pratsyuє в pototsі zukhvaloї програма и за svoіh zmіnnyh vikoristov стека zukhvalі програми. Іstotnoy vіdmіnіstyu roboti процедури в динамичен sv'yazuvannі (vіd статично) є sposіb vstanovlenya zv'yazku.

Дейвид Драйсдейл, ръководство за начинаещи за линкери

(http://www.lurklurk.org/linkers/linkers.html).

Мета статии – Помогнете на програмистите на C и C++ да разберат същността на това, което прави линкерът. През останалите години обяснявах на големия брой колеги и открих, че е дошло времето да прехвърля този материал на хартия, така че да стане достъпен (а аз нямах възможност да го обяснявам отново). [Актуализация през март 2009 г.: Добавена е допълнителна информация за спецификата на оформлението на Windows, както и правилото за една дефиниция по-подробно.

Типичен задник на това, което преди мен беше изпратено за помощ, това е такова извинение за оформлението:

g++ -o test1 test1a.o test1b.o

test1a.o(.text+0x18): Във функция `main':

: недефинирана препратка към `findmax(int, int)"

collect2: ld върна 1 статус на изход

Ако реакцията ви е „повторно забравяне на външното „С““, тогава Вие, който знаете всичко, знаете всичко, което се индуцира в тази статия.

  • Обозначение: какво има във файла C?
  • Какво да ограби C компилатора
  • Как да ограбите линкера: част 1
  • Какво да ограбим операционната система
  • Какво да ограбите линкера: част 2
  • C++ подобряване на изображението
  • Динамично натоварени библиотеки
  • Добавково

Обозначение: какво има във файла C?

Tsey razdіl - кратко предположение за различните складове C файл. Ако всичко в списъка по-долу може да е сензация за вас, тогава, по-добре за всичко, можете да пропуснете този раздел и веднага да преминете към офанзивата.

На гърба е необходимо да се разбере разликата между зашеметените и назначените.

Предназначен да показва im'ya с реализацията, която може да бъде код или дани:

  • Посочено от променящия се компилатор, е възможно да се резервира зоната на паметта за деня, като се зададе стойността на името.
  • Определената функция zmushu компилаторът генерира код на функция

Какъвто и да е компилаторът, кои функции са назначени или променени (със едни и същи имена) е достъпен в различна програмна област, очевидно, в различен C файл. (Да върна уважението, че и назначението е гръмогласно - всъщност е шумно, на някое "друго място" програмите вървят с точното).

За промяната е обозначението на два вида:

  • глобални промени, yakі іsnuyut protyazhu shogo zhyttєvogo циклови програми ("статично разположение") и yakі, достъпни от различни функции;
  • локални промени, yakі іsnuyut іlki іn между deykoї ї ї ї ї ї ї ї scho vykonuєtsya („местно разположение“) и yakі на разположение іtlki іn в средата на ієї ї ї ї функции.

Когато използвате термина „достъпен“, следващото нещо, което трябва да разберете, е „можете да включите името, свързано с промяната, в момента на назначаването“.

Има няколко okremih vipadkіv, yakі z първия път не дават очевидното:

  • статични локални променинаистина глобално, до това, което се основава на протяга на целия живот на програмата, за да мирише така, сякаш се вижда само в границите на една функция.
  • статични глобални променисъщо е глобално с tієyu razniceyu, че смърдите са достъпни само в границите на един файл, де смърди се присвояват.

Warto означава, че чрез означаване на статична функция, малък брой места лесно се съкращават, сред които можете да се обърнете към функцията на име.

За глобални и локални промени можем да разделим първоначалната промяна, т.е. chi bude prostir, vіdvedeniya за zminnoї pom'yati, zapovneno пеят стойности.

И сега можем да запазим информацията в паметта, както се вижда динамично за помощ malloc или new. В тази ситуация няма възможност да се обърнете към гледката на паметта върху името, така че е необходимо да спечелите демонстрантите - имената на промяната, да отмъстите за адреса на неназованата област на паметта. Областта на паметта Tsya може да бъде извикана за помощ безплатно или изтриване. Според мен може да сме вдясно с динамичните разположения.

Предложено:

Глобални

Местни

Динамичен

Neіnítsia-

Neіnítsia-

goloshennia

int fn(int x);

extern int x;

extern int x;

Назначаване

int fn(int x)

{ ... }

int x = 1;

(област dії

файл)

intx;

(област dії - файл)

int x = 1;

(домейн dії - функция)

intx;

(домейн dії - функция)

int*p = malloc(sizeof(int));

Имовирно повече лесен начинВземете го - просто се чудете на задника на програмата.

/* Обозначаване на неинициализирана глобална промяна */

int x_global_uninit;

/* Инициализирана глобална промяна на дестинацията */

int x_global_init = 1;

/* Обозначаване на неинициализираната глобална промяна, до

static int y_global_uninit;

/* Обозначаване на инициализираната глобална промяна, до

* можете да разглеждате по име само в границите на всеки C файл */

static int y_global_init = 2;

/* Унищожаване на глобалната промяна, както е дефинирана тук

* в друга област на програмата */

extern int z_global;

/* Оттеглена функция, присвоена на друго място

* програми (Можете обаче да добавите "extern" отпред

* не е обовязково) */

int fn_a(int x, int y);

/* Определена функция. Въпреки това, като е определена като статична, тя може

* Щракнете върху името само в границите на този C файл. */

статичен int fn_b(int x)

връщане x+1;

/* Определена функция. */

/* Параметърът на функцията се спазва от локалната промяна. */

int fn_c(int x_local)

/* Обозначаване на неинициализирана локална промяна */

int y_local_uninit;

/* Обозначение на инициализирана локална промяна */

int y_local_init = 3;

/* Код, който се преобразува в локални и глобални промени,

* както и функции на im'ya */

X_global_uninit = fn_a(x_local, x_global_init);

Y_local_uninit = fn_a(x_local, y_local_init);

Y_local_uninit += fn_b(z_global);

връщане (x_global_uninit + y_local_uninit);

Какво да ограби C компилатора

p align="justify"> Роботът на C компилатора трябва да преобразува текста на (изключително) разумни хора, в това, което компютърът разбира. При излизане компилаторът вижда обектния файл. На UNIX платформи ci файловете могат да се наричат ​​suffix.o; за Windows - suffix.obj. Промяна на обектния файл - по същество две думи:

код, който показва конкретна функция в C файл

данни, които определят стойността на глобалните промени във файла C (за инициализиране на глобалните промени, стойността на промяната може да бъде запазена в обектния файл).

Код и данни, понякога, matimut, свързани с него имена - имената на функциите на тези, които се променят, от които те са свързани с назначения.

Обектният код е последователността (в реда на сгъване) от машинни инструкции, които следват C инструкциите, написани от програмиста: всички if "and while" и goto. Това заклинание се дължи на манипулиране на информацията на пеещото семейство и информацията може да бъде de-nebud - за когото трябва да се променим. Кодът може да се отнася и до друг код (кодът за други функции на C в програмата).

Въпреки че би-декодирането се отнася до промяната на която и да е функция, компилаторът го позволява, само ако е известно предварително дали промяната или функцията се променят. Goloshennya - tse obitsyanka, която е назначена тук в друга област на програмата.

Роботът на асемблера трябва да провери отново броя на obitsyanki. Как обаче компилаторът работи с обичайната употреба, ако генерира обектен файл?

Всъщност компилаторът запълва празни пространства. Празно място (възможност) може да бъде назовано, но значението, което е дадено на това име, все още не се вижда.

Vahovuchi tse, можем да покажем обектен файл, който показва програмата, задържайки курсора повече, като това:

Анализ на обектен файл

Доси ми гледаше на всичко на най-равностойно ниво. Prote се чуди как работи на практика. Основният инструмент ще бъде командата nm, която предоставя информация за символите на обектния файл на UNIX платформата. За команда на windows dumpbin от опцията /symbols е приблизителен еквивалент. Има също Windows портове на инструментите GNU binutils, които включват nm.exe.

Нека видим как изглежда nm за обектен файл, взет от задника:

Символи от c_parts.o:

Име Стойност Клас Тип Размер Линия Раздел

fn_a | | U | БЕЛЕЖКА | | |*UND*

z_global | | U | БЕЛЕЖКА | | |*UND*

fn_b | 00000000 | t | FUNC | 00000009 | |.текст

x_global_init | 00000000 | D | ОБЕКТ | 00000004 | |.данни

y_global_uninit | 00000000 | б | ОБЕКТ | 00000004 | |.bss

x_global_uninit | 00000004 | в | ОБЕКТ | 00000004 | |*COM*

y_global_init |00000004| г | ОБЕКТ | 00000004 | |.данни

fn_c | 00000009 | T | FUNC | 00000055 | |.текст

Резултатът може да изглежда малко по-различно на различни платформи (върни се към човека, за да вземеш съответната информация), но ключовите думи са класът на символа на кожата и yogo rosemir (което е є). Класът може да има различни значения :

  • Клас U означава невидими съобщения, вие самите „празно място“, гадаене. За този клас има два обекта: fn_a и z_global. (Някои версии на nm могат да показват секцията или чрез *UND* или UNDEF по какъвто начин искате.)
  • Клас t и T показват кода, който е значението; разликата между t и T в това, което е локалната функция (t) във файла chi n (T), т.е. функцията bula се озвучава като статична. Ами знам, че в някои системи може да се покаже секция например.
  • Класове d и D за отмъщение на глобалните промени. Коя статична промяна принадлежи към клас d. Ако има информация за секцията, тогава тя ще бъде.data.
  • За неинициализирани глобални промени ще приемем b, който е статичен и B или C в противен случай. Разделът ще бъде по-добър за всичко. bss или *COM*.

Можете също да използвате символи, като част от външния C код. Няма да обръщаме внимание на това, така че част от вътрешния механизъм на компилатора да звучи, така че програмата ви да може да бъде компилирана по-късно.

Линкер (или редактор на връзки) на присвояванията за свързване между себе си обектни файлове, които се генерират от компилатора, както и библиотечни файлове, които влизат в системата за програмиране.

Обектният файл (или колекция от обектни файлове) не може да бъде копиран с точка, докинговете на всички модули и секции няма да бъдат свързани помежду си. За да убиете редактора на връзки (линкер). Резултатът от йога е един файл, заглавия, zavantazhuvalnym модул.

Capture module – софтуерен модул, който е прикачен за улавяне и модифициране, който се взема от обектния модул при редактиране на връзки и програмата разглежда последователността на машинните команди.

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

Функцията на линкера е проста. Започвате работата си, като избирате секцията на програмата и дадения имейл адрес от първия обектен модул. Програмните секции на други обектни модули приемат адресите на произволен адрес в реда на директност. С това можете да видите и функцията за преглед на имейл адресите на секциите на програмата. В същото време текстовете на секциите на програмата ще бъдат комбинирани с раздели с данни, таблици с идентификатори и имена на повиквания. Разрешени са заявки за напречни сечения.

Процедурата е позволено да бъде изградена до изчисляване на стойността на адресните константи на процедурите, функциите и промените за преместване на секции като началото на програмния модул. Ако е така, съобщенията се изпращат до zvnіshnіh zminnyh, като в списъка с обектни модули, редактора на връзките в организацията на техните търсения в библиотеките, налични в системата за програмиране. Е, библиотеката не трябва да знае за склада, тя формира информация за помилването.

Извикайте линкера, за да образувате най-простия софтуерен модул, който работи заедно като един. Въпреки това, повече сгъваеми греблаЛинкерът може да създава други модули: програмни модули със структура на наслагване, библиотечни обектни модули и библиотечни модули, които са динамично свързани.

Повече обектни модули съвременни системиПрограмирането ще се базира на така наречения известен адрес. Компилаторът, който генерира обектни файлове, а след това линкерът, който ги комбинира в един, не могат да знаят със сигурност в коя реална област от паметта на компютъра ще се намира програмата в момента на изтегляне. Ето защо работи не с реални адреси в средата на RAM, а с реални външни адреси. Такива адреси се присвояват на първата интелигентна точка, взета като глава на областта на паметта, тъй като получената програма се заема (озвучава точката на главата на първия модул на програмата).

Очевидно същата програма не може да бъде хакната на тези външни адреси. За това е необходим модул, който преобразува известния адрес в реални (абсолютни) адреси без посредник в момента на стартиране на програмата на viconnanny. Този процес се нарича адрес за превод и специфичен модул, чиито заглавия са наименувани.

Vantazhuvach обаче не стартира системата за програмиране на склада, парчетата от функциите, които са изградени върху него, вече лежат под формата на централна архитектура система за броене, В този случай получената програма се създава от системата за програмиране. На първите етапи разработването на ОС се основаваше на разглеждане на едни и същи модули, те въвеждаха адреса на излъчване и подготвяха програмата до края - създаваха заглавието „образ на задачата“. Такава схема беше типична за богата ОС (например за RTOS на EOM тип CM-1, OS RSX / 11 или RAFOS на EOM тип CM-4 също). Изображението на задачата може да бъде запазено за към носталгичния носв противен случай направете йога отново в най-ранния час от подготовката на програмата до края.

От развитието на архитектурата изброяване на предимстватаКомпютърът успя да вземе адреса на излъчване без посредник в момента, в който програмата беше стартирана в ритъма. За което е необходимо да се съхранява файлът, който трябва да се провери, включва отделна таблица, която трябва да бъде изпратена на адреса, тъй като е необходимо да се изпрати излъчването. В момента на стартиране на хакнатия файл ОС обработи следната таблица и превърна познатите адреси в абсолютни. Такава схема, например, е прикрепена към ОС като MS-DOS. В тази схема модулът се приема като такъв ежедневен (всъщност влиза в склада на ОС), а системата за програмиране отговаря само за подготовката на адреса на таблицата за превод - тази функция е да изгради линкера.

Съвременните операционни системи имат метод на сгъване и преобразуване на адреси, така че да могат да се обработват без прекъсване едновременно със следващия час от програмата. Qi методи за основаване на възможностите, хардуерни ипотеки в архитектурата броещи комплекси. Методите за преобразуване на адреси могат да се основават на сегментна, странична и сегментна организация на паметта. Todi за vykonannya излъчване адрес в момента на стартиране на програмата може да се подготвят съответните системни таблици. По-вероятно е тези функции да паднат върху модулите на ОС, така че зловонието е в системите за програмиране.

Статии преди четене:

Как да премина към Miui 9 Stable Global от китайски фърмуер? Деблокиране на завантажувача



компилатор за препроцесор (7)

Искам да разбера как част от компилатора на винената програма е изненадана и какво се опитва да направи линкерът. Затова написах следния код:

#включи използване на пространство от имена std; #включи < class paramType >void FunctionTemplate(paramType val) (i = val)); test void Тест :: DefinedCorrectFunction (int val) ( i = val ; ) void Тест :: DefinedIncorrectFunction (int val ) ( i = val ) void main () ( Test testObject (1 ); //testObject.NonDefinedFunction(2);//testObject.FunctionTemplate (2); }

Имам три функции:

  • DefinedCorrectFunction - ce нормална функция, озвучено и правилно идентифицирано.
  • DefinedIncorrectFunction - тази функция е декларирана правилно, но изпълнението е неправилно (в деня;)
  • NonDefinedFunction - няма повече глупости. Няма уговорка.
  • FunctionTemplate - шаблон на функция.

    Сега, когато компилирам този код, отнемам извинението на компилатора за ежедневния ";" в DefinedIncorrectFunction.
    Добре, ще го коригирам и ще коментирам testObject.NonDefinedFunction (2) по-късно. Сега ще отнема извинението на линкера. Сега коментирайте testObject.FunctionTemplate(2). Сега ще премахна извинението на компилатора за ежедневно ";".

За функционални шаблони разбирам, че смрадът не се чете от компилатора, защото смрадът не се отразява в кода. Отже, видсутни ";" не се притеснявайте за компилатора, не съм щракнал върху testObject.FunctionTemplate (2).

За testObject.NonDefinedFunction (2), компилаторът не се поколеба, но линкерът го направи. Доколкото знам, целият компилатор е виновен за благородство, че функцията NonDefinedFunction беше заклеймена. Vіn dbav за zdіysnennya. Тогава линкерът изръмжа, защото не знаех изпълнението. Всичко върви добре.

Ето защо не знам как да изградя компилатор и как да изградя линкер. Моето разбиране за компонентите на линкера беше написано с моите собствени уикита. Също така, ако NonDefinedFunction е именуван, проверете дали реализацията на NonDefinedFunction е компилирана и се кълнете. Но компилаторът не добави за внедряването на NonDefinedFunction, но работи за DefinedIncorrectFunction.

Имам повече от желание, така че ако можете да го обясните или помогнете на дякона.

Компилаторът проверява повторно, chi валидира изходния код на филма и интерпретира семантиката на филма. Компилатор visnovok – цял обектен код.

Linker poov'yazuє различни обектни модули наведнъж, schob форма exe. Определени функции за разпространение на следващия етап, а на следващия етап се добавя правилният код на текущата седмица.

Компилаторът компилира кода, сякаш е един превод. Ще компилирате целия код, който включва изходния файл.
DefinedIncorrectFunction() се присвоява на изходния файл, така че компилаторът го проверява за валидност.
NonDefinedFunction() може да бъде присвоен на изходен файл, тогава компилаторът няма да трябва да го компилира, ако е присвоен на друг изходен файл, функцията ще бъде компилирана като част от превода, но вместо дъщерен етап на обаждането на срещата няма да бъде намерено от линкера, тогава той ще извика извинението на обаждането.

Функцията на компилатора е отговорна за компилираненапишете своя код и го конвертирайте в обектни файлове. Така че защо сте пропуснали; в противен случай името на победителя не се променя, компилаторът ще се закълне, за това има синтактични извинения.

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

  1. Заглавки - информация за файла
  2. Обектен код - машинен код (този код не може да бъде обработен сам в повечето случаи)
  3. Информация за преместване. Някои части от кода ще трябва да променят адресите за действителното въвеждане
  4. Таблица със символи- Символи, върху които е приложен кодът. Вонята може да се припише на tsyumuкодове, импортирани от други модули или определени от линкера
  5. Vіdlagodzhuvalna іinformatsija - печалба от собствениците

Компилаторът компилира кода и попълва таблицата със символи със символ на кожата, с който се придържат вината. Символите се виждат преди промяна и функции. Захранването обяснява таблицата със символи.

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

Следващото посочване

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

Създадените обектни файлове се обработват от линкер, който запълва празнините в таблиците със символи, свързва един модул с друг i, намира го, дава код, от който може да се възползва.

И така, какво ще кажете за вашата конкретна випадка -

  1. DefinedIncorrectFunction() - компилаторът премахва дефинираната функция и започва да я компилира, за да създаде обектен код и да вмъкне заместващ знак в таблицата със символи. Компилационна прошка чрез синтактично извинение, така че компилаторът се прекъсва с помилване.
  2. NonDefinedFunction () - компилаторът приема декларация, ако не може да бъде присвоена, след това добавете запис към таблицата със символи и използвайте линкера, за да добавите посочените стойности (линкерът на линкера обработва колекцията от обекти, вероятно обозначението присъства в . Не посочвате дали има друг файл за вашия тип, така че линкерът е прекъснат Моля недефинирана препратка към NonDefinedFunctionтака че не можете да знаете какво е необходимо за валиден запис в таблицата със символи.

За по-голяма яснота, нека кажем отново, че вашият структурен код е такъв:

#включи #включи class Test ( private : int i ; public : Test (int val ) ( i = val ;) void DefinedCorrectFunction (int val); void DefinedIncorrectFunction (int val); void NonDefinedFunction (int val); шаблон< class paramType >void FunctionTemplate(paramType val) (i = val;));

try.cpp файл

#include "try.h" test void Test :: DefinedCorrectFunction (int val) ( i = val ; ) void Test :: DefinedIncorrectFunction (int val ) ( i = val ; ) int main () ( Test testObject (1 ); testObject Функцията (2) не е назначена; //testObject.FunctionTemplate (2); връщане на 0; )

Нека просто копираме и поставим кода, но не го извикваме

$ g++ - c опитайте. cpp-o опитайте. o $

Тази култура тече без ежедневни проблеми. И така, имате обектния код на try.o. Опитайте да се обадите на Його

$ g++ опитайте. o опитайте. o : Във функция ` main " : опитайте . cpp : (. text + 0x52 ): недефинирана препратка към ` Тест : Недефиниран

Забравихте да дефинирате Test::NonDefinedFunction. Нека се включим смислено йога okremumuфайл.

Файл-try1.cpp

#include "try.h" void Test :: NonDefinedFunction (int val) (i = val;)

Компилиране на йога в обектен код

$ g++ - c try1. cpp-o try1. o $

Е, знам, успешно е. Опитвам се да свържете допълнителен файл

$ g++ опитайте1. o/usr/lib/gcc/x86_64-redhat-linux/4.4. 5 /../../../../lib64/crt1. o : Във функция ` _start ": (. text + 0x20 ): недефинирана препратка към ` main " collect2 : ld върна 1 статус на изход

Нито едно основно нещо не е толкова изиграно!

Сега имате два отделни об'ектни кода, в които са всички необходими компоненти. Просто изпратете и двете към линкера

$ g++ опитайте. o опитайте 1. o $

Без милост!! Необходимо е линкерът да знае значението на всички функции (например да попълни празнините в обектните кодове с подходящи стойности)

Кажи ми, ако искаш да хапнеш супа, иди в ресторанта.

Разгледайте менюто за супа. Ако не познавате йога в менюто, ще напуснете ресторанта. (на окото на компилатора, да се страхува от тези, които не могат да знаят функцията). откъде знаеш какво правиш?

Обаждате се на сервитьора да поръча супата. Но това, че виното е в менюто, не означава, че мирише в кухнята. Може би менюто е остаряло, може би, след като е забравил да каже на готвача, че супата е виновна. Така че ще отида отново. (например извинение за свързващия, който не може да знае символа)

Точката, с която е неприемливо, е синтактично извинение, кодът не е виновен за компилиране. Можете също да използвате внедряването на шаблона. По същество това е етап на синтактичен анализ и въпреки че е очевидно за човек как да „коригира и подсилва“, компилаторът не е виновен за тази работа. Не можете просто да „разкриете, че сте двугърда жена, за това сте онези, които са малки по пътя си“ и да продължите.

Компилаторът търси функции за уикито там, необходимо е de stenk. Тук няма нужда от нищо, няма скарга за това. Няма извинения за този файл, необходимо е да се изведат камъните, необходимо е, не може да се приложи в този конкретен блок от компилация. Компонентът е даден за избор на различни компилационни блокове, така че да се "свържат".

Тези, които изграждат компилатора, и тези, които изграждат линкера, го поставят в реализацията: законната реализация може просто да запази токенизациите на dzherelo в компилатора и да работи всичко в линкера. Текущи реализации мустакповече въвеждане на линкера, за кратка оптимизация. Имах много ранни реализации на шаблоните, не се удивлявах на кода за шаблона до сега, до часът на достатъчност, ще има достатъчно, за да разпозная, когато шаблонът свърши. От вида на потребител е по-вероятно да се кикате, chi є извинете "необходима диагностика" (тъй като може да бъде взета от компилатор или линкер) chi е неоткриваемо поведение.

По време на DefinedIncorrectFunction можете да намерите текста, който е необходим за анализа. Tsey текст за отмъщение за помилване, тъй като изисква диагностика. В случай на NonDefinedFunction: ако функцията е спечелена, командата трябва да бъде присвоена (в противен случай присвояването е повече от едно) в нова програмає нарушаване на едно правило за отдаденост, като е неопределено поведение. Диагностиката не е необходима (но не мога да покажа изпълнението, тъй като не дадох желания резултат поради липсата на победна функция).

На практика помилванията, които лесно могат да се разглеждат просто като начин за превод на текста в един блок от превод, се обозначават със стандарта за „диагностика на изображенията“ и ще бъдат показани от компилатора. Pomelka, Yakі не могат да бъдат wiwed на Perevіrtsі Okarenio Odinitska кръстовище (thyroidis, Vіdysten, Yaku Bethi е присъщо на същите асансьори) е формално невидимо поведение - при развъждането на филц можете да направите бутик с компонент и в такива випади.

Той е променен по такъв начин, сякаш са въведени функции, че ви е позволено да повторите обозначението в скинната единица на превода и да променяте шаблоните над езика, фрагментите на богатите помилвания не могат да се показват до създаването на копието . В крайна сметка стандартът предоставя голяма свобода за внедряването на шаблони: когато компилаторът е виновен, той носи отговорността да анализира достатъчно шаблона, за да определи, де шаблонът завършва. Стандартът обаче е добавил такава реч, като typename , за да позволи повече синтактичен анализ преди създаването на екземпляра. Въпреки това, в други контексти, подобни извинения не могат да се проявят преди създаването на копието, което може да бъде времето на компилация, или в часа на ранно изпълнение, така че след създаването на създаването в момента на часа; компилация до часа, който доминира днес и печели VC ++ и g ++.

Компилаторът е виновен за свързване към присвоения код (евентуално) външни модули- Библиотеки или обектни файлове, тъй като ще хакнете наведнъж с този конкретен изходен файл, за да генерирате нов файл. Освен това, тъй като сте сляп, но няма нищо лошо, вашият код ще бъде компилиран, така че компилаторът да знае, че линкерът може да знае грешката тук. Следователно в този случай вие приемате извинението като линкер, а не компилатор.

Обаче, от друга страна, кодът има синтактично извинение, компилаторът не може да компилира и вие приемате помилване на този етап. Макросите и шаблоните могат да се държат по различен начин, но не и да призовават за помилване, за да не смърдят (шаблони са почти в същия стил, повече макроси с по-голям интерфейс за приемане), но и да лежат в лицето на тежестта на помилването. Ако архивирате стилове, които компилаторът не може да разбере, декомпозирате шаблона от шаблона/макроса и стартирате оригиналния код, не можете да го компилирате.

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

Интересува ме каква е вашата храна:

Там, където се обърках, компилаторът се оплака от DefinedIncorrectFunction. Вижте изпълнението на NonDefinedFunction и след това преминете през DefinedIncorrectFunction.

Компилаторът е опитал съвпадението на DefinedIncorrectFunction (защото вие сте дали заданието в избрания изходен файл) и е произведено синтактично извинение (има ежедневно петънце с буца). От друга страна, компилаторът в никакъв случай не е в състояние да обозначи NonDefinedFunction, защото просто нямаше код в този модул. Възможно е NonDefinedFunction да е присвоена на NonDefinedFunction в различен изходен файл, но компилаторът не знае кой. Компилаторът преглежда само единизходен файл (и няколко включени заглавни файла) наведнъж.

Операционни системи (ОС)