LEARN - Сайт групи 08-308 МАІ

int main(void) < #if MAX>99 printf("Компілює для масиву, розмір якого більше 99.\n"); #endif

return 0; > Це програма виводить повідомлення на екран, тому що МАХ більше 99. Директива #else працює в основному так, як else - ключове слово мови С: задає альтернативу на той випадок, якщо не виконано умову #if. Попередній приклад можна доповнити так: /* Простий приклад #if/#else. */ #include

int main(void) < #if MAX>99 printf("Компілює для масиву, розмір якого більше 99.\n"); #else printf("Компілює для невеликого масиву.\n"); #endif

return 0; > У цьому випадку з'ясовується, що МАХ менше 99, тому частина коду, що стосується #if, не компілюється. Однак компілюється альтернативний код, що стосується #else, і відкомпільована програма відображатиме повідомлення Компілюється для невеликого масиву. Директива #elif означає "else if" і встановлює для безлічі варіантів компіляції ланцюжок if-else-if. Після #elif знаходиться константний вираз. Якщо це вираз істинно, то компілюється блок коду, що знаходиться за ним, і більше не перевіряються ніякі інші вирази #elif. В іншому випадку перевіряється наступний блок цієї послідовності. У загальному вигляді #elif виглядає таким чином: #if вираз послідовність операторів #elif вираз 1 послідовність операторів #elif вираз 2 послідовність операторів #elif вираз 3 послідовність операторів #elif вираз 4 . . . #elif вираз N послідовність операторів #endif Наприклад, у наступному фрагменті для визначення знака грошової одиниці використовується значення ACTIVE_COUNTRY (для якої країни): #define US0 #define ENGLAND 1 #define FRANCE 2

#define ACTIVE_COUNTRY US

#if ACTIVE_COUNTRY == US char currency[] = "dollar"; #elif ACTIVE_COUNTRY == ENGLAND char currency[] = "pound"; #else char currency[] = "franc"; #endif Відповідно до стандарту С89 у директив #if і #elif може бути не менше 8 рівнів вкладеності. А відповідно до стандарту С99 програмістам дозволяється використовувати щонайменше 63 рівнів вкладеності. При вкладеності кожна директива #endif, #else або #elif належить до найближчої директиви #if або #elif. Наприклад, цілком правильним є наступний фрагмент коду: Директиви #ifdef і #ifndef Інший спосіб умовної компіляції - це використання директив #ifdef і #ifndef, які відповідно означають "if defined" (якщо визначено) та "if not defined" (якщо не визначено). У загальному вигляді #ifdef виглядає так: #ifdef имя_макроса послідовність операторів #endif Блок коду буде компілюватися, якщо ім'я макросу було визначено раніше в операторі #define. У загальному вигляді оператор #ifndef виглядає так само як і #ifdef чином: Блок коду компілюватиметься, якщо ім'я макросу ще не визначено в операторі #define. І в #ifdef, і в #ifndef можна використовувати оператор #else або #elif. Наприклад, #include

int main(void) < #ifdef TED printf("Привіт, Тед\n"); #else printf("Привіт, хтось\n"); #endif #ifndef RALPH printf("А RALPH не визначено, т.ч. Ральфу не пощастило.\n"); #endif

return 0; > виведе Привіт, Тед, а також RALPH не визначено, т.ч. Ральфу не пощастило. Відповідно до стандарту С89 допускається не менше 8 рівнів #ifdef і #ifndef. А стандарт С99 встановлює, що має підтримуватись не менше 63 рівніввкладеності.

Трансляція + Редагування зв'язків (комапонування).

Ключі компонувальника задають режими роботи компонувальника, найчастіше використовується ключ -l, що задає імена системних бібліотек об'єктних модулів. Системні бібліотеки зберігаються в каталозі /lib або /usr/lib, а їхні імена починаються з lib і закінчуються .a. Наприклад, стандартна бібліотека Сі називається libc.a (ця бібліотека використовується завжди і її вказувати не потрібно), бібліотека математичних функцій зберігається у файлі libm.a. З використанням ключа -l необхідно вказати оригінальну частину імені системної бібліотеки, тобто. для використання libm.a необхідно вказати ключ -lm. Вихідні_модулі це імена одного або декількох файлів із закінченням .c, що містять тексти програм на Сі. Об'єктні_модулі це імена одного або декількох файлів з розширенням .o, що містять об'єктні модулі, які будуть використані для отримання виконуваної програми.

3.1. Введення в бібліотеки Як уже неодноразово згадувалося в попередньому розділі, бібліотека - це набір скомпонованих особливим чином об'єктних файлів. Бібліотеки підключаються до основної програми під час лінкування. За способом компонування бібліотеки поділяють на архіви (статичні бібліотеки, static libraries) та спільно використовувані (динамічні бібліотеки, shared libraries). У Linux, крім того, є механізми динамічного підвантаження бібліотек. Суть динамічного підвантаження полягає в тому, що запущена програма може на власний розсуд підключити до себе бібліотеку.

Опція -l, передана компілятору, обробляється і надсилається лінковнику для того, щоб той підключив до бінарника бібліотеку. Як ви вже помітили, у імені бібліотеки "обрубані" префікс та суфікс. Це робиться для того, щоб створити"видима байдужість" між статичними та динамічними бібліотеками. Зараз важливо знати лише те, що бібліотека libfoo.so і бібліотека libfoo.a підключаються до проекту опцією -lfoo. У нашому випадку libworld.a "урізалося" до -lworld. Опція -L вказує лінковнику, де шукати бібліотеку. Якщо бібліотека знаходиться в каталозі /lib або /usr/lib, то питання відпадає саме собою і опція -L не потрібна. У нашому випадку бібліотека знаходиться у репозиторії (у поточному каталозі). За замовчуванням лінковник не переглядає поточний каталог пошуку бібліотеки, тому опція -L. (точка означає поточний каталог) потрібна.

-Lкаталог Додати каталог до списку каталогів, які містять об'єктні бібліотечні модулі. -lБібліотека Під час редагування зв'язків підключити модулі з бібліотеки.

Бібліотека(у програмуванні, від англ. library) - Збірник підпрограм або об'єктів для вирішення близьких за тематикою завдань. З погляду ОС та прикладного ПЗ бібліотеки поділяються на: динамічні та статичні. Також називаються бібліотеки загального користування або бібліотеки, що розділяються (англ. shared library) або бібліотеки, що динамічно підключаються (англ. Dynamic Link Library, DLL). Це окремі файли, що надають прикладним програмам набір функцій, що найчастіше використовуються, і завантажуються на етапі виконання при зверненні програми до ОС із заявкою на виконання функції з бібліотеки. Якщо запрошена бібліотека вже завантажена в ОЗУ, програма користуватиметься завантаженою копією. Такий підхід дозволяє зберегти пам'ять, оскільки кілька програм використовують одну копію бібліотеки, завантажену в пам'ять. Динамічні бібліотеки зазвичай зберігаються в певному місці і мають стандартне розширення. Наприклад, файли .library у логічному томіLibs: в AmigaOS; у Microsoft Windows та OS/2 файли бібліотек загального користування мають розширення .dll; в UNIX-подібних ОС - зазвичай .so; в MacOS - .dylib. При написанні програми програмісту достатньо вказати транслятору мови програмування (компілятору або інтерпретатору), що слід підключити таку бібліотеку і використовувати таку функцію із зазначеної бібліотеки. Ні вихідний текст, ні код функції, що виконується, до складу програми не входить. Можуть бути у вигляді вихідного тексту, що підключається програмістом до своєї програми на етапі написання (наприклад, для мови Fortran існує величезна кількість бібліотек для вирішення різних завдань саме у вихідних текстах), або у вигляді об'єктних файлів, що приєднуються (лінкуються) до виконуваної програмі на етапі компіляції (у Microsoft Windows такі файли мають розширення .lib, UNIX‐подібних ОС — зазвичай .a). У результаті програма включає всі необхідні функції, що робить її автономною, але збільшує розмір. DLL (англ. Dynamic-link library — бібліотека, що динамічно підключається) — поняття операційної системи Microsoft Windows; динамічна бібліотека, що дозволяє багаторазове застосування різними програмними програмами. До DLL належать також елементи керування ActiveX та драйвери. У світі UNIX аналогічні функції виконують т. зв. shared objects («об'єкти, що розділяються»). Спочатку передбачалося, що введення DLL дозволить ефективно організувати пам'ять та дискове простір, використовуючи лише одну інстанцію бібліотечних модулів для багатьох програм. Це було особливо важливо для ранніх версій Microsoft Windows із жорсткими обмеженнями пам'яті. Далі, передбачалося поліпшити ефективність розробок та використання системних засобів за рахунок модульності. Заміна DLL-програм з однієї версії наіншу мала дозволити незалежно нарощувати систему, не торкаючись додатків. Крім того, бібліотеки DLL могли використовуватися різнотипними програмами - наприклад, Microsoft Office, Microsoft Visual Studio і т. п. Надалі ідея модульності зросла в концепцію COM. Фактично, повних переваг від впровадження DLL отримати не вдалося через явище, зване DLL_hell («пекло DLL»). DLL Hell виникає, коли кілька додатків вимагають одночасно різні, не повністю сумісні, версії DLL-бібліотек, що призводить до збоїв у цих додатках. Коли система зросла до певних розмірів, кількість DLL стала перевищувати багато тисяч, не всі з них мали повну надійність і сумісність, і конфлікти типу DLL Hell стали виникати дуже часто, різко знижуючи загальну надійність системи. Пізні версії Microsoft Windows стали дозволяти паралельне використання різних версій DLL, що звело нанівець переваги початкового принципу модульності.

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

За допомогою утиліти make можна не тільки швидко створити файл, що виконується, але також і задати деякі скрипти використовуючи операцію clear: і run: Також можна задати окреме створення об'єктного файлу і якщо є об'єктний файл, то окремо створення виконуваного файлу. В утиліті make об'єктні файли та виконуваний файли можна задати як змінні. Можна також вибрати компілятор. Розглянемо приклад: є бібліотека stack.h, програма stack.c, де описані всі функції бібліотеки stack.h і main файл lab26.c, всі вони знаходяться у папці scr. Об'єктний файл stack.o міститься у папці tmp.

СС=gcc #вибір компілятора CFALGS = -c -std = c99 -Wall

all: objects prog #завдання цілей

objects: ./tmp/stack.o #створення об'єктного файлу

./tmp/stack.o: ./scr/stack.c ./scr/stack.h

$(CC) $(CFALGS) -o ./tmp/stack.o ./scr/stack.c

prog: ./lab26 #виконуваного файлу ./lab26: ./scr/lab26.c objects $(LD) $(LDFLAGS) -o ./lab26 ./scr/lab26.c ./tmp/ stack.o

clear: #скрипт видаляє дані з даної папки rm -i ./lab26 ./tmp/* ./scr/*

run: make all #скрипт створює файл, що виконується, і відразу запускає його ./lab26