Препроцесор C
Препроцесор С/С++ — програмний інструмент, який використовується в мовах програмування C та C++, препроцесор, що змінює код програми для подальшої компіляції й збірки.
Мова препроцесора C/C++ не є повною за Тюрингом хоча б тому, що за допомогою директив неможливо змусити препроцесор «зависнути».
Директиви
Директивою препроцесора називається рядок у коді, який має такий вигляд #ключове_слово параметри
. Є чітко визначений список ключових слів:
define
— Задає макровизначення (макроси) або константуundef
— Скасовує попереднє визначенняinclude
— Вставляє текст з зазначеного файлу (імпортує)if
— Здійснює умовну компіляцію при істинності константного виразуifdef
— Здійснює умовну компіляцію, якщо константа визначенаifndef
— Здійснює умовну компіляцію при невизначеності константиelse
— Гілка умовної компіляції при хибності висловлюванняelif
— Гілка умовної компіляції, утворена злиттям else і ifendif
— Кінець гілки умовної компіляціїline
— Препроцесор змінює номер поточного рядка і ім'я файлу для компіляціїerror
— Висвітлення повідомлення з зупинки компіляціїpragma
— Дію, що залежить від конкретної реалізації компілятораwarning
— Висвітлення повідомлення без зупинки компіляції- порожня слово — пуста дія
Опис директив
Константи і макроси #define
Константи і макроси препроцесора використовуються для визначення невеликих фрагментів коду. Зазвичай константи визначаються за допомогою великих літер.
// константа
#define BUFFER_SIZE 1024
#define PI 3.14
// макрос
#define NUMBER_OF_ARRAY_ITEMS(array) (sizeof(array)/sizeof(*(array)))
Кожна константа і кожен макрос замінюються відповідним їм визначенням. Макроси мають параметри, схожі на функції, використовуються для зменшення коду.
Приклад визначення макросу max
, який приймає два аргументи: a
і b
та вертає більше з двох число:
#define max( a, b ) ( (a) > (b) ? (a) : (b) )
Макрос викликається як звичайна функція:
z = max(x, y);
Після заміни макроса код буде виглядати наступним чином:
z = ((x) > (y) ? (x) : (y));
Директива #include
#include
При виявленні директив #include "..."
або #include <...>
, де «…» — ім'я файлу, препроцесор читає вміст зазначеного файлу, виконує директиви і заміни (підстановки).
Для #include "..."
пошук файлу виконується в цій папці і папках, зазначених в командному рядку компілятора. Для #include <...>
пошук файлу виконується в папках, що містять файли стандартної бібліотеки (шлях до цих папок залежать від компілятора).
Файли, що включаються зазвичай містять:
- оголошення функцій;
- оголошення глобальних змінних;
- визначення інтерфейсів;
- визначення типів даних;
- структури
- та інше.
Директива #include
зазвичай вказується на початку файлу (в заголовку), тому включаються файли називаються заголовками.
Приклад включення файлів із стандартної бібліотеки мови C:
#include <math.h> // імпортування математичних функцій(стандартна бібліотека)
#include <foo.h> // імпортування файлу не зі стандартної бібліотеки
Використання препроцесора вважається неефективним з наступних причин:
- кожен раз при включенні файлів виконуються директиви і заміни (підстановки); компілятор міг би зберігати результати препроцессірованія для використання в майбутньому;
- множинні включення одного файлу доводиться запобігати вручну за допомогою директив умовної компіляції; компілятор міг би виконувати цю задачу самостійно.
Починаючи з 1970-х років стали з'являтися способи, якими замінено включення файлів. У мовах Java і Common Lisp використовуються пакети (ключове слово package
) (див. Package в Java ), в мові Паскаль — англ. units (ключові слова unit
і uses
), у мовах Modula, OCaml, D, Haskell і Python — модулі. Використовуються ключові слова module
і import
.
Посилання
- The C Preprocessor (англ.)