Анимация
JavaScript
|
Главная Библионтека a(); \ b(); \ } else но я думаю, что комбинация do с while (0) незначительно лучше. Так как вы можете объявить переменную после любой открытой фигурной скобки, то у вас появляется возможность использования предшествующего метода для определения макроса, имеющего по существу свои собственные локальные переменные. Рассмотрим следующий макрос, осуществляющий обмен значениями между двумя целочисленными переменными: #define swap int(x,y) \ do \ int x##y; \ x##y = x; \ x = y; \ y = x##y \ while (0) Сочетание ## является оператором конкатенации в стандарте ANSI Си. Я использую его здесь для обеспечения того, чтобы имя временной переменной не конфликтовало с любым из имен исходных переменных. При данном вызове: swap(laurel, hardy); препроцессор вначале подставляет аргументы обычным порядком (заменяя x на laurel, а y на hardy), давая в результате следующее имя временной переменной: int laurel##hardy; Затем препроцессор удаляет знаки решетки, давая int laurelhardy; Дополнительная польза от возможности замены макросов функциями заключается в отладке. Иногда вы хотите, чтобы что-то было подобно макросу по эффективности, но вам нужно при отладке установить в нем точку прерывания. Используйте для этого в Си++ встроенные функции, а в Си используйте следующие: #define AT LEFT(this)((this)->left child is thread ? NULL\ :(this)->left) #ifdef DEBUG static tnode *at left(tnode *this) { return AT LEFT(this); } #else # define at left( this) AT LEFT(this) #endif Я закончу это правило упоминанием о еще двух причудливых конструкциях, которые иногда полезны в макросе, прежде всего потому, что они помогают макросу расширяться в один оператор, чтобы избежать проблем с фигурными скобками, рассмотренных ранее. Положим, вы хотите, чтобы макрос по возможности расширялся в единственное выражение. Оператор последовательного вычисления достигает этого в ущерб читаемости, и наряду с ним я никогда не использую формы, показанные в таблице 1 , по той же причине - их слишком трудно читать. (Коли на то пошло, я также не использую их в макросах, если я могу достичь желаемого каким-то другим способом). Таблица 1. Макросы, эквивалентные условным операторам
Первые два выражения опираются на тот факт, что вычисления в выражении с использованием операций && и гарантированно осуществляются слева направо и прекращаются сразу, как только устанавливается истина или ложь. Возьмем для примера выражение a&& f(). Если a ложно, то тогда не важно, что возвращает f(), так как все выражение ложно, если любой из его операндов значит ложь. Следовательно, компилятор никогда не вызовет f() , если a ложно, но он должен вызвать f() , если a истинно. То же самое применимо и к b, но здесь f() вызывается, если b, напротив, ложно. 81.1. Операция ?: не то же самое, что и оператор if/else Последняя строка в таблице 1 относится к другому спорному вопросу. Условная операция - это простой оператор. Она используется лишь в выражении и передает значение. Условная операция является не очень привычной заменой для оператора if/else, но не менее, чем операции && или приемлемы для замены простого if. Хотя большинство людей и не принимают во внимание замену: if(z) i=j; else i=k; z&&(i=j); z(i = k); Мне довелось случайно увидеть подобное этому, но с использованием условной операции: z?(i = j):(i = k); Все предыдущие фрагменты в равной мере способны сбить с толку. Следующий код показывает, как надлежащим образом использовать условную операцию, и ее результат яснее (т.е. лучше), чем у равноценного оператора if/else: i = z?j:k; 81.2. Помещайте тело макроса и его аргументы в круглые скобки Это правило одно из основных, но я обнаружил, что множество людей, пользующихся Си ежедневно, его забыли. Вот классическая задача: #define TWO K 1024 + 1024 что при использовании в: 10 * TWO K расширяется до: 10* 1024 + 1024 вычисляемого как: (10 * 1024) + 1024 Решаем эту задачу при помощи круглых скобок: #define TWO K (1024 + 1024) Вот сходная задача в следующем фрагменте кода: #define SQUARE(x) (x * x) Определено: SQUARE(y + 1); 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 [ 33 ] 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |