Лекція 3. Функції та синтаксис С. Компілятори, команди та бібліотеки

1.    Мова програмування С

C – універсальна, процедурна, імперативна мова програмування загального призначення, розроблена у 1972 році Денісом Рітчі в Bell Telephone Laboratories з метою написання нею операційної системи UNIX.

Хоча С і було розроблено для написання системного програмного забезпечення, зараз вона досить часто використовується для написання прикладного програмного забезпечення.

C здійснила великий вплив на інші мови програмування, особливо на C++, яку спочатку проектували як розширення для С, а також на Java та C#, які запозичили у С синтаксис.

С – мінімалістична мова програмування. Серед її головних цілей: можливість прямолінійної реалізації компіляції, використовуючи відносно простий компілятор, забезпечити низькорівневий доступ до оперативної пам'яті, формувати лише кілька інструкцій машинної мови для кожного елементу мови і не вимагати великої динамічної підтримки. У результаті код С придатний для більшості системного програмного забезпечення, яке традиційно писали асемблером.

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

 

2. Характеристика

Як і більшість імперативних мов, C має можливості для структурного програмування і дозволяє здійснювати рекурсії, у той час, як система статичної типізації даних запобігає виникненню багатьох непередбачуваних операцій. У С весь виконуваний код міститься у функціях. Параметри функції завжди передаються за значеннями. Передача параметрів за вказівником реалізовується шляхом передачі значення вказівника. Гетерогенні сукупності типів даних (структури) дозволяють пов'язаним типам даних бути об'єднаними і маніпулювати ними, як єдиним цілим.

Основні особливості С:

  • проста мовна база, з якої в стандартну бібліотеку винесено багато істотних можливостей, на зразок математичних функцій або функцій роботи з файлами;
  • орієнтація на процедурне програмування;
  • система типів, що оберігає від безглуздих операцій;
  • використання препроцесора для абстрагування однотипних операцій;
  • доступ до пам'яті через використання вказівників;
  • невелике число ключових слів;
  • передача параметрів в функцію за значенням, а не за посиланням (передача за посиланням емулюється за допомогою вказівників);
  • наявність вказівників на функції і статичних змінних;
  • області видимості імен;
  • структури і об'єднання – визначені користувачем збірні типи даних, якими можна маніпулювати як одним цілим.

У той же час в С відсутні:

  • вкладені функції;
  • пряме повернення декількох значень з функцій;
  • підпрограми;
  • засоби автоматичного керування пам'яттю;
  • вбудовані засоби об'єктно-орієнтованого програмування;
  • засоби функціонального програмування.

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

 

3. Синтаксис С

Алфавіт мови

У мові використовуються всі символи латинського алфавіту, цифри і деякі спеціальні символи:

  • Символи латинського алфавіту: A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z
  • Цифри: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  • Спеціальні символи: , (кома), . (крапка), +, -, *, ^, & (амперсанд), =, ~ (тильда), !, /, <, >, (, ), {, }, [, ], |, %, ?, '(апостроф), "(лапки), : (двокрапка), _ (знак підкреслення), \, #

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

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

Cимвол # не може бути частиною ніякої лексеми і використовується в препроцесорах.

Ідентифікатори

Допустимий ідентифікатор – це слово, до складу якого можуть входити символи латинського алфавіту, цифри і знак підкреслення. Ідентифікатори даються операторам, константам, змінним, типам і функціям.

Деякі ідентифікатори є ключовими і не можуть бути використані в програмі в якості ідентифікаторів програмних об'єктів. Існують і зарезервовані ідентифікатори, на використання яких компілятор не видасть помилок, але які в майбутньому можуть стати ключовими словами, що спричинить за собою несумісність.

Літеральні константи

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

Цілі числа за замовчуванням задаються в десятковій системі числення. Якщо зазначений префікс 0x, то – в шістнадцятковій системі. Префікс у вигляді цифри 0 вказує, що число задається в вісімковій системі. Суфікс визначає мінімальний розмір типу константи, а також визначає, чи є число знаковим або беззнаковим. В якості підсумкового типу береться такий мінімально можливий, в якому дану константу можна представити.

Іменовані константи

В мові С для задання констант прийнято використовувати макроозначення, які оголошуються за допомогою директиви препроцесора #define:

#define ім'я константи [значення]

Ключові слова

Ключові слова – це ідентифікатори, призначені для виконання того чи іншого завдання на етапі компіляції, або для підказок і вказівок компілятору.

Визначені в С ключові слова: sizeof, typedef, auto, register, extern, static, void, char, short, int, long, signed, unsigned, float, double, const, volatile, struct, enum, union, do, for, while, if, else, switch, case, default, break, continue, goto, return, inline, restrict.

Зарезервовані ідентифікатори

Крім ключових слів стандарт мови визначає зарезервовані ідентифікатори, використання яких може привести до несумісності з майбутніми версіями стандарту. Зарезервованими є всі, за винятком ключових, слова, що починаються зі знака підкреслення (_), після якого йде або велика літера (A-Z), або інший знак підкреслення.

Коментарі

Текст програми на С може містити фрагменти, які не є частиною програмного коду, – коментарі. Коментарі спеціальним чином позначаються в тексті програми і пропускаються при компіляції.

Спочатку, в стандарті C89, були доступні вбудовані коментарі, які могли міститися між послідовностями символів / * та * /.

Наступний стандарт, C99, ввів ще один спосіб оформлення коментарів: коментарем вважається текст, що починається з послідовності символів // і закінчується кінцем рядка.

Змінні

При оголошенні змінної вказується її тип і назва, а також може зазначатися початкове значення:

[описувач] [ім'я];

або

[описувач] [ім'я] = [ініціалізатор];

де

[описувач] – тип змінної і попередні типу необов'язкові модифікатори;

[ім'я] – ім'я змінної;

[ініціалізатор] – початкове значення змінної, що присвоюється при її створенні.

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

4.    Компілятори та інтерпретатори

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

Мова, на якій представлена вхідна програма, називається вихідною мовою, а сама програма – вихідним кодом. Вихідна мова називається цільовию мовою, а вихідна (результуюча) програма – об'єктним кодом.

Мета трансляції – перетворення тексту з однієї мови на мову, зрозумілу адресату. При трансляції комп'ютерної програми адресатом може бути:

  • пристрій – процесор (трансляція називається компіляцією);
  • програма – інтерпретатор (трансляція називається інтерпретацією).

Види трансляції:

  • компіляція;
  • інтерпретація;
  • динамічна компіляція.

Мова процесора називається машинною мовою, машинним кодом. Код на машинній мові виконується процесором.

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

Процес компіляції, як правило, складається з декількох етапів:

  • лексичний аналіз;
  • синтаксичний аналіз;
  • семантичний аналіз;
  • створення на основі результатів аналізів проміжного коду;
  • оптимізація проміжного коду;
  • створення об'єктного коду, в даному випадку машинного.

Переваги компіляції:

  • компіляція програми виконується один раз;
  • наявність компілятора на пристрої, для якого компілюється програма, не потрібна.

Недоліки компіляції:

  • компіляція – повільний процес;
  • при внесенні змін до початкового коду, потрібна повторна компіляція.

Асемблер – компілятор, що перетворює текст з мови асемблера на машинну мову. Мова асемблера – мова, близька до машинної мови, мова низького рівня.

Інтерпретація – процес читання і виконання вихідного коду. Реалізується програмою-інтерпретатором.

Інтерпретатор може працювати двома способами:

  • читати код і виконувати його відразу (чиста інтерпретація);
  • читати код, створювати в пам'яті проміжне представлення коду (байт-код або p-код), виконувати проміжне представлення коду (змішана реалізація).

У першому випадку трансляція не використовується, а в другому – використовується трансляція вихідного коду в проміжний код.

Етапи роботи інтерпретатора:

  • лексичний аналіз;
  • синтаксичний аналіз;
  • семантичний аналіз;
  • створення проміжного представлення коду (при чистій інтерпретації не виконується);
  • виконання.

Інтерпретатор моделює віртуальну машину, реалізує цикл вибірки-виконання команд машини. Команди машини записуються на машинній мові, а на мові високого рівня. Інтерпретатор можна назвати виконавцем мови віртуальної машини.

Переваги інтерпретаторів в порівнянні з компіляторами:

  • можливість роботи в інтерактивному режимі;
  • відсутність необхідності перекомпіляції вихідного коду після внесення змін і при перенесенні коду на іншу платформу.

Недоліки інтерпретаторів в порівнянні з компіляторами:

  • низька продуктивність;
  • необхідність наявності інтерпретатора на пристрої, на якому планується інтерпретація програми;
  • виявлення помилок синтаксису на етапі виконання (актуально для чистих інтерпретаторів).

Динамічна або JIT компіляція – трансляція, при якій вихідний або проміжний код перетворюється (компілюється) в машинний код безпосередньо під час виконання, «на льоту». Компіляція кожної ділянки коду виконується тільки один раз; скомпільований код зберігається в кеші і при необхідності використовується повторно.

Переваги динамічної компіляції в порівнянні з компіляцією:

  • швидкість роботи динамічно компільованих програм близька до швидкості роботи компільованих програм;
  • відсутність необхідності перекомпіляції програми при перенесенні на іншу платформу.

Недоліки динамічної компіляції в порівнянні з компіляцією і чистою інтерпретацією:

  • велика складність реалізації;
  • великі вимоги до ресурсів.

Динамічна компіляція добре підходить для веб-додатків.

Динамічна компіляція з'явилася і підтримується в тій чи іншій мірі в реалізаціях Java, .NET Framework, Perl, Python.

  

5. Бібліотеки

Бібліотека в програмуванні – збірник функцій або об'єктів, які використовуються для розробки програмного забезпечення (ПЗ).

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

При написанні програми програмістові досить вказати транслятору (компілятору або інтерпретатору) шлях до бібліотеки і ім'я функції. Ні вихідний текст функції, ні її виконуваний код до складу програми не увійдуть.

Стандартною бібліотекою мови С називається частина стандарту ANSI C, присвячена заголовним файлам і бібліотечним підпрограмам. Це опис реалізації спільних операцій, таких як обробка введення-виведення і текстових рядків, в мові програмування С.

Ім'я та характеристики кожної функції вказуються у файлі, іменованому заголовним файлом, але поточна реалізація функцій описана окремо в бібліотечному файлі.

Стандартна бібліотека зазвичай поставляється разом з компілятором. Так як компілятори мови С часто забезпечують розширену функціональність, не визначену стандартом ANSI C, стандартна бібліотека одного компілятора несумісна зі стандартними бібліотеками інших компіляторів.

Файли вихідного коду компілюються окремо і повинні включати прототипи імпортованих з інших файлів змінних, функцій і типів даних. Для цього використовується включення заголовних файлів через макропідстановки #include. Оскільки директива #include лише підставляє текст одного файлу в інший, включення великої кількості заголовків файлів призводить до того, що багато разів зростає фактичний обсяг коду, що потрапляє на компіляцію, що є причиною щодо низької швидкості роботи компіляторів мови С. Необхідність узгодження описів в основному модулі і заголовних файлах ускладнює супровід програми.

Остання зміна: Thursday 28 May 2020 02:35 AM