Define, програмування на c і ​​c

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

#define імя_макроса последовательность_сімволов

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

Наприклад, якщо необхідно використовувати TRUE для значення 1, a FALSE для 0 то можна оголосити наступні два макроси:

#define TRUE 1
#define FALSE 0

В результаті, якщо компілятор виявить в тексті програми TRUE або FALSE, то він замінить їх на 1 і 0 відповідно. Наприклад, наступний рядок виводить на екран «0 1 2»:

printf ( "...", FALSE, TRUE, TRUE + 1);

У разі, якщо макрос визначений, він може використовуватися для визначення інших макросів. Наприклад, наступний код зіставляє з іменами ONE, TWO і THREE їх чисельні значення:

#define ONE 1
#define TWO ONE + ONE
#def ine THREE ONE + TWO

В результаті макропідстановки ідентифікатори заміщуються зазначеними рядками. Якщо не-обходимо визначити стандартне повідомлення про помилку, то можна написати щось на зразок сліду-ющего:

#define E_MS "Standart error on input. \ n"
/ *. * /
printf (E_MS);

Якщо компілятор виявляє ідентифікатор E_MS, то він заміщає його рядком «Standart error on input.» Насправді компілятор побачить оператор у вигляді

printf ( "Standart error on input. \ n");

Якщо ідентифікатор знаходиться в рядку, то підстановка не відбувається. наприклад:

#define XYZ this is a test
/ *. * /
printf ( "XYZ");

виведе не "this is a test», a «XYZ».

Якщо рядок не вміщається в одному рядку, то її можна продовжити на наступному рядку, помістивши в кінці рядка зворотний слеш, як показано в наступному прикладі:

#define LONG_STRING "This is a very long" \
string that is used as an example. "

Програмісти, що пишуть на С, часто використовують великі літери для визначення ідентифік-торів. Дана угода допомагає будь-якій людині, що читає програму, кинувши на неї один погляд, дізнатися, що він має справу з макросом. Також вce #define краще поміщати на початку файлу або взагалі в окремий заголовний файл.

Дуже часто макроси використовують для визначення «магічних чисел», використовуваних в про-грамі. Наприклад, програма може визначати масив і мати кілька процедур для роботи з ним. Замість того, щоб жорстко кодувати розмір масиву, краще визначити макрос, відпо-відний розміром масиву, і використовувати його в тих місцях, де необхідне використання раз-міра. Таким чином, якщо необхідно змінити розмір масиву, єдине, що потрібно зробити, - це змінити оператор #define і перекомпіліровать програму. Скрізь, де вико-вався даний макрос, відбудуться автоматичні зміни. Розглянемо приклад:

#define MAX_SIZE 100
/ *. * /
float balance [MAX_SIZE];
/ *. * /
float temp [MAX_SIZE];

Для зміни розмірів обох масивів просто змінимо визначення MAX_SIZE.

Директива #define має ще одну можливість: макрос може мати аргументи. Кожен раз при зустрічі такого макросу аргументи макросу будуть заміщатися реальними аргументами про-грами. Такий тип макроса називається макрос типу функція. наприклад:

#include
#define MIN (a, b) ((a)<(b)). (a). (b)
int main (void)
int x, y;
x = 10; у = 20;
printf ( "The minimum is:.", MIN (x, y));
return 0;
>

При компіляції програми замість MIN (a, b) підставляється вказане вираз, причому замість фіктивних параметрів а і b підставляються реальні х і у. Таким чином, в результаті підстановки функція printf () прийме наступний вигляд:

printf ( "The minimum is:.", ((x) <(y) ). (x). (y) );

Треба бути обережним при визначенні макросів, які отримують аргументи, або можна напів-чить дещо несподівані результати. Наприклад, розглянемо наступну коротку програм-му, що використовує макрос для визначення парності значення:

/ * Програма видає неправильний результат * /
#include
#define EVEN (a) a% 2 == 0. 1. 0
int main (void)
if (EVEN (9 + 1)) printf ( "is even");
else printf ( "is odd");
return 0;
>

Через способу підстановки дана програма не працює належним чином. В результаті компіляції програми EVEN (9 + 1) розшириться до

Як відомо, оператор взяття по модулю має більш високий пріоритет, ніж оператор сло-вання. Це означає, що спочатку виконається взяття по модулю з числом 1, а потім результат буде додане над 9, що, природно, не може дорівнювати 0. Для усунення даної проблеми сле-дует укласти а в макросі EVEN в круглі дужки, як показано в наступній правильної вер-сії програми:

#include
#define EVEN (a) (a)% 2 == 0. 1. 0
int main (void)
if (EVEN (9 + 1)) printf ( "is even");
else printf ( "is odd");
return 0;
>

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

Схожі статті