русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Заміна макросів


Дата додавання: 2014-11-28; переглядів: 957.


Визначення макроса має форму

#define назва текст-заміни

Це вимагає найпростішої заміни макроса — наступні появи лексеми «назва» буде замінено «текстом заміни». Назва в #define має ту саму форму, що й назви змінних; текст заміни може бути довільним. Зазвичай текст заміни розміщено на тому самому рядкові, але якщо треба продовжити його на наступних, додайте зворотню похилу \ вкінці кожного рядка, який ви хочете продовжити. Зона дії назви, означеної #define, починаєтьсся з пункту, де її було означено і аж до кінця файла, який буде компільовано. Визначення можуть вживати попередні визначення. Заміни матимуть місце тільки для лексем і не відбуваються всередині ланцюжків взятих у лапки. Скажімо, якщо YES — це означена назва, заміна стане неможливою у випадку printf("YES")або YESMAN. Назву можна пов'язати з будь-яким текстом заміни. Наприклад

#define forever for(;;) /* нескінчений цикл */

визначає для нескінченого циклу нове слово — forever.

Можна також означити макроси з аргументами, тож текст заміни зможе відрізнятися для різних викликів макроса. Для прикладу, створимо макрос під назвою max:

#define max(A, B) ((A) > (B) ? (A) : (B))

Хоч це й виглядає ніби виклик функції, виклик max розкривається у вбудований код. Кожна поява формального параметра (у цьому випадку A й B) замінюватиметься на відповідні дійсні аргументи. Таким чином, рядок

x = max(p+q, r+s);

замінюється на

x = ((p+q) > (r+s) ? (p+q) : (r+s));

Доки аргументи вживаються несуперечливо, цей макрос служитиме для будь-якого типу даних; немає потреби у відмінному max для іншого типу даних, як це відбувається у функціях.

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

max(i++, j++); /* НЕПРАВИЛЬНО */

здіснить приріст більшого значення двічі. Треба також звертати увагу на дужки, щоб упевнитись, що порядок обчислень збережено; уявіть, що станеться якщо макрос

#define square(x) x * x /* НЕПРАВИЛЬНО */

викликати як square(z+1).

Не зважаючи на це, макроси корисні. Один з прикладів їхнього використання на практиці можна знайти в <stdio.h>, де getchar і putchar часто означено як макроси, щоб запобігти втраті робочого часу на виклик функції для кожного опрацьованого знака. Функції у <ctype.h>також часто втілено як макроси.

Назви можна скасувати за допомогою #undef, зазвичай, щоб упевнитись, що якась функція є справді функцією а не макросом:

#undef getchar

 

int getchar(void) { ... }

Формальні праметри не замінюються, якщо іх було взято у лапки при означенні макроса. Проте, якщо попереду назви параметра стоїть знак # у тексті заміни, комбінація розшириться до взятого в лапки ланцюжка, у якому параметр заміниться на фактичний аргумент. Це можна комбінувати зі зчепленням ланцюжків, наприклад для відлагодження макросу виводу:

#define dprint(expr) printf(#expr " = %g\n", expr)

Якщо його викликати як

dprint(x/y)

макрос розкриється у

printf("x/y" " = %g\n", x/y);

ланцюжки буде зчеплено, тож отримаємо

printf("x/y = %g\n", x/y);

Всередині отриманого аргументу, кожний знак " замінюється на \" і кожний \ на \\, тож результат буде допустимою ланцюжковою константою.

Оператор препроцесора ## дає можливість зчепити дійсні аргументи під час розкриття макросу. Якщо параметр у тексті заміни є суміжним з ##, цей параметр буде замінено на дійсний аргумент, ## і оточуючі пробіли усунуто і результат переглянуто. Наприклад, наступний макросpaste зчеплює власні два аргументи:

#define paste(front, back) front ## back

тож paste(name, 1) створить лексему name1.

Правила гніздованого використання ## досить заплутані; подальші деталі ви знайдете у Додатку А.

Вправа 4-14. Означте макрос swap(t,x,y), який міняє місцями два аргументи типу t. (Тут поможе блокова структура коду.)


<== попередня лекція | наступна лекція ==>
Включення файлів | Обумовлене включення файлів


Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн