|
Программирование >> Решение нетривиальных задач
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. Хотя большинство людей 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); и не принимают во внимание замену: if( z ) i = j; else i = k;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |