Директиви препроцесора використовують для керування процесом компіляції та попередньої модифікації тексту програми. Наведемо ті директиви, які визначаються стандартом мови С++.
Наступні директиви називають директивами умовної компіляції:
#if
#ifdef
#else
#elif
#endif
Вони дозволяють або не дозволяють виконувати компіляцію певних частин програми залежно від виконання умов. Такі директиви застосовуються, якщо треба отримати декілька версій виконуваного коду програми.
Директива
#include
дозволяє включити текст з іншого файлу у текст поточної програми. Наприклад, такий рядок
#include "dalmat.h"
призведе до включення файлу "dalmat.h" у текст програми замість рядка самої директиви. Файл "dalmat.h" буде шукатися спочатку у поточній папці. Якщо там його не буде знайдено, пошук буде здійснюватися у системних папках, шляхи до яких прописані у оточенні процесору (у тому числі у каталозі \INCLUDE ). Ім’я файлу можна писати також у кутових дужках:
#include <dalmat.h>
У такому разі пошук файлу для заміни буде вестись одразу у системних папках.
Директива
#define
дозволяє створювати макроси. Розрізняють три види макросів:
- макроси - ідентифікатори;
- макроси заміни;
- макрос-функції.
Макроси-ідентифікатори мають найпростішу конструкцію:
#define ім’я
Застосовуються вони для умовної компіляції.
Макрос заміни записується таким чином:
#define ім’я послідовність_символів
Такий макрос призводить до заміни в тексті програми всіх входжень послідовності символів ім’я на вказану послідовність_символів.
Макрос-функція теж призводить до певних замін, але вони виконуються по іншим правилам. Розглянемо такий приклад:
#define MIN(A,B) ((A)<(B)) ? (A) : (B)
Тепер кожен раз, коли у програмі буде зустрічатися MIN(A,B), замість нього буде підставлено вираз ((A)<(B)) ? (A) : (B). При цьому у якості A,B може бути записано довільну послідовність символів.
Наведемо два приклади більш-менш вдалого використання макросу заміни та макрос-функції. У стандартному пакеті Borland C++ константу p розташовано під ім’ям M_PI . Якщо ми бажаємо використовувати її під більш зручним ім’ям pi , треба у початку програми записати такий макрос:
#define pi M_PI
У такий же спосіб можна замість імені математичної функції обчислення тангенсу tan(x) задіяти більш звичне у математиці ім’я tg(x). Для цього потрібно записати такий макрос:
#define tg(x) tan(x)
У старих технологіях програмування макроси заміни часто використовуються для реалізації у програмі констант, а макрос-функції можуть застосовуватись як звичайні функції. Але тут має сенс застережити: в обох вказаних випадках будуть суттєво послаблені можливості діагностування помилок на етапі компіляції. У зв’язку з цим рекомендується застосовувати інші засоби для реалізації констант і функцій.
Наступна директива
#undef ім’я
відміняє визначення макросу з вказаним ім’ям.
Директива
#line
застосовується для зміни змісту напередвизначених макросів __LINE__ та __FILE__ . Макрос __LINE__ містить у собі номер рядка у тексті програми, а макрос __FILE__ - ім’я вихідного файлу з програмою, яка виконується.
Директива
#error повідомлення
припиняє компіляцію з виведенням повідомлення.
Директива
#pragma ім’я
застосовується для надання певної інструкції компілятору.
Ряд макросів, які є символьними константами, компілятор визначає автоматично. Такі макроси діляться на дві групи: макроси ANSI і додаткові макроси, які генеруються компілятором (наприклад, компілятором Borland C++). До макросів ANSI, зокрема, відносяться такі:
__DATE__ - рядок, що містить дату компіляції у форматі mmm dd yyyy;
__TIME__ - рядок, що містить час компіляції у форматі hh:mm:ss;
__FILE__ - рядок, що містить ім'я поточного файлу в подвійних лапках.
Умовна компіляція фрагменту програми
Розглянемо деякий фрагмент програми (звичайно це є набір функцій). Запишемо його із застосуванням директив #ifdef та #endif у такий спосіб:
#ifdef _MM_