
Умовна компіляція
Умовна компіляція також дозволяє програмісту-розробнику маніпулювати ресурсами стандартної бібліотеки, а саме – управляти виконанням директив препроцесора і компіляцією програмного коду. Кожна із умовних директив препроцесора оцінює значення цілочисельного виразу. В директивах препроцесора неможлива оцінка виразів приведення типів, виразів sizeof i констант перечислення.
Конструкції умови препроцесора в цілому подібні на оператор умови if. Розглянемо наступний код препроцесора:
#if !defined(NULL)
#define NULL 0
#endif.
Ці директиви встановлюють, чи визначений символ NULL. Вираз defined(NULL) має значення 1, якщо NULL визначений, і 0 в протилежному випадку. Якщо результат – 0, !defined(NULL) приймає значення 1 і виконується визначення NULL. В протилежному випадку директива #define пропускається. Кожна конструкція #if закінчується #endif. Директиви #ifdef i #ifndef – це скорочення для #if defined(ім’я) і #if !defined(ім’я). Умовні конструкції препроцесора, що перевіряють декілька варіантів, реалізуються за допомогою директив #elif (еквіваленту else if структури if) і #else (еквіваленту else структури if).
При розробці програм програмісти, що уникнути компіляції великих частин програми, часто перетворюють їх в тимчасові коментарії. Якщо сам код програми містить коментарії, то /* і */ символи для цього не підходять. В даному випадку можна використовувати наступну конструкцію препроцесора:
#if 0
Код, компіляцію якого не потрібно здійснювати
#endif
Щоб дозволити знову компілювати фрагмент коду, потрібно замість аргументу 0 вставити 1 при операторі #if.
Умовна компіляція часто служить середовищем, яке допомагає відладити програму. При відладці програми можна використовувати відладчик або оператор printf, щоб вивести на друк значення аргументів чи змінних і пересвідчитися в правильності ходу виконання програми. Якщо такі оператори заключити в директиви умовної компіляції препроцесора, то їх компіляція буде виконуватися тільки в період відладки. Наприклад:
#ifdef DEBUG
printf ("Variable x = %d\n", x);
#endif
приведе до того, що оператор printf буде компілюватися в програмі, якщо перед директивою #ifdef DEBUG була визначена (#define DEBUG) символічна константа DEBUG. Коли відладка завершена, директива #define видаляється із вихідного файла і оператори printf, вставлені для мети відладки, будуть при компіляції ігноруватися. В великих програмах бажано визначити декілька символічних констант, щоб мати можливість контролювати умови компіляції окремих частин вихідного файла.
Директиви #error I #pragma
Директива #error
#error лексеми виводить на друк залежне від реалізації повідомлення, включаючи лексеми, визначені в директиві. Лексеми – це послідовності символів, розділені пробілами. Так директива
#error 1 – Out of range error
містить шість лексем-ресурсів. Коли виконується директива #error, лексеми в ній відображаються як повідомлення про помилку (що залежить від системи); потім препроцесор зупиняється і програма не компілюється.
Директива #pragma
#pragma лексеми вказує дію, залежну від реалізації.
Вказівка: все нерозпізнане даним компілятором ігнорується.
Операції # i ## в мові С
Операції # i ## наявні тільки в бібліотеці стандартної мови С. Операція # виконує перетворення текстової лексеми в лінійку, яка буде заключена в лапки. Розглянемо наступне макровизначення:
#define HELLO(x) printf ("Hello, " #x "\n");
Коли в файлі програми з’являється вираз Hello(John), він поширюється в printf ("Hello, " "John" "\n");
Лінійка "John" перетворюється в текст заміни замість #x. Препроцесор здійснює конкатенацію лінійок, що розділені тільки символами пробілу, а тому, попередній оператор еквівалентний:
printf ("Hello, John \n");
Відмітимо, що операція # повинна використовуватися в макросах з аргументами, оскільки операнд після # посилається на аргумент макросу.
Операція ## виконує конкатенацію двох лексем. Розглянемо наступне макровизначення:
#define TOKENCONCAT(x,y) x ## y.
Коли TOKENCONCAT з’являється в тексті програми, проходить конкатенація його аргументів, після чого вони заміняють макровизначення. Наприклад, TOKENCONCAT(О,К) заміщується в програмі на ОК. Операція ## повинна мати два операнди.